欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C#網(wǎng)絡(luò)編程之Socket編程

 更新時(shí)間:2022年02月25日 08:46:43   作者:.NET開(kāi)發(fā)菜鳥(niǎo)  
本文詳細(xì)講解了C#網(wǎng)絡(luò)編程的Socket編程,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下

一:什么是SOCKET

socket的英文原義是“孔”或“插座”。作為進(jìn)程通信機(jī)制,取后一種意思。通常也稱(chēng)作“套接字”,用于描述IP地址和端口,是一個(gè)通信鏈的句柄(其實(shí)就是兩個(gè)程序通信用的)。
socket非常類(lèi)似于電話插座。以一個(gè)電話網(wǎng)為例:電話的通話雙方相當(dāng)于相互通信的2個(gè)程序,電話號(hào)碼就是ip地址。任何用戶在通話之前,首先要占有一部電話機(jī),相當(dāng)于申請(qǐng)一個(gè)socket;同時(shí)要知道對(duì)方的號(hào)碼,相當(dāng)于對(duì)方有一個(gè)固定的socket。然后向?qū)Ψ綋芴?hào)呼叫,相當(dāng)于發(fā)出連接請(qǐng)求。對(duì)方假如在場(chǎng)并空閑,拿起電話話筒,雙方就可以正式通話,相當(dāng)于連接成功。雙方通話的過(guò)程,是一方向電話機(jī)發(fā)出信號(hào)和對(duì)方從電話機(jī)接收信號(hào)的過(guò)程,相當(dāng)于向socket發(fā)送數(shù)據(jù)和從socket接收數(shù)據(jù)。通話結(jié)束后,一方掛起電話機(jī)相當(dāng)于關(guān)閉socket,撤銷(xiāo)連接。

套接字分類(lèi)

為了滿足不同程序?qū)νㄐ刨|(zhì)量和性能的要求,一般的網(wǎng)絡(luò)系統(tǒng)都提供了以下3種不同類(lèi)型的套接字,以供用戶在設(shè)計(jì)程序時(shí)根據(jù)不同需要來(lái)選擇:

流式套接字(SOCK_STREAM):提供了一種可靠的、面向連接的雙向數(shù)據(jù)傳輸服務(wù)。實(shí)現(xiàn)了數(shù)據(jù)無(wú)差錯(cuò),無(wú)重復(fù)的發(fā)送,內(nèi)設(shè)流量控制,被傳輸?shù)臄?shù)據(jù)被看做無(wú)記錄邊界的字節(jié)流。在TCP/IP協(xié)議簇中,使用TCP實(shí)現(xiàn)字節(jié)流的傳輸,當(dāng)用戶要發(fā)送大批量數(shù)據(jù),或?qū)?shù)據(jù)傳輸?shù)目煽啃杂休^高要求時(shí)使用流式套接字。

數(shù)據(jù)報(bào)套接字(SOCK_DGRAM):提供了一種無(wú)連接、不可靠的雙向數(shù)據(jù)傳輸服務(wù)。數(shù)據(jù)以獨(dú)立的包形式被發(fā)送,并且保留了記錄邊界,不提供可靠性保證。數(shù)據(jù)在傳輸過(guò)程中可能會(huì)丟失或重復(fù),并且不能保證在接收端數(shù)據(jù)按發(fā)送順序接收。在TCP/IP協(xié)議簇中,使用UDP實(shí)現(xiàn)數(shù)據(jù)報(bào)套接字。

原始套接字(SOCK_RAW):該套接字允許對(duì)較低層協(xié)議(如IP或ICMP)進(jìn)行直接訪問(wèn)。一般用于對(duì)TCP/IP核心協(xié)議的網(wǎng)絡(luò)編程。

二:SOCKET相關(guān)概念

1、端口

在Internet上有很多這樣的主機(jī),這些主機(jī)一般運(yùn)行了多個(gè)服務(wù)軟件,同時(shí)提供幾種服務(wù)。每種服務(wù)都打開(kāi)一個(gè)Socket,并綁定到一個(gè)端口上,不同的端口對(duì)應(yīng)于不同的服務(wù)(應(yīng)用程序),因此,在網(wǎng)絡(luò)協(xié)議中使用端口號(hào)識(shí)別主機(jī)上不同的進(jìn)程。
例如:http使用80端口,F(xiàn)TP使用21端口。

2、協(xié)議

2.1 TCP:

TCP是一種面向連接的、可靠的,基于字節(jié)流的傳輸層通信協(xié)議。為兩臺(tái)主機(jī)提供高可靠性的數(shù)據(jù)通信服務(wù)。它可以將源主機(jī)的數(shù)據(jù)無(wú)差錯(cuò)地傳輸?shù)侥繕?biāo)主機(jī)。當(dāng)有數(shù)據(jù)要發(fā)送時(shí),對(duì)應(yīng)用進(jìn)程送來(lái)的數(shù)據(jù)進(jìn)行分片,以適合于在網(wǎng)絡(luò)層中傳輸;當(dāng)接收到網(wǎng)絡(luò)層傳來(lái)的分組時(shí),它要對(duì)收到的分組進(jìn)行確認(rèn),還要對(duì)丟失的分組設(shè)置超時(shí)重發(fā)等。為此TCP需要增加額外的許多開(kāi)銷(xiāo),以便在數(shù)據(jù)傳輸過(guò)程中進(jìn)行一些必要的控制,確保數(shù)據(jù)的可靠傳輸。因此,TCP傳輸?shù)男时容^低。

2.1.1 TCP的工作過(guò)程

TCP是面向連接的協(xié)議,TCP協(xié)議通過(guò)三個(gè)報(bào)文段完成類(lèi)似電話呼叫的連接建立過(guò)程,這個(gè)過(guò)程稱(chēng)為三次握手,如圖所示:

第一次握手:建立連接時(shí),客戶端發(fā)送SYN包(SEQ=x)到服務(wù)器,并進(jìn)入SYN_SEND狀態(tài),等待服務(wù)器確認(rèn)。

第二次握手:服務(wù)器收到SYN包,必須確認(rèn)客戶的SYN(ACK=x+1),同時(shí)自己也發(fā)送一個(gè)SYN包(SEQ=y),即SYN+ACK包,此時(shí)服務(wù)器進(jìn)入SYN_RECV狀態(tài)。

第三次握手:客戶端收到服務(wù)器的SYN+ACK包,向服務(wù)器發(fā)送確認(rèn)包ACK(ACK=y+1),此包發(fā)送完畢,客戶端和服務(wù)器進(jìn)入Established狀態(tài),完成三次握手。

2.1.2 傳輸數(shù)據(jù)

一旦通信雙方建立了TCP連接,連接中的任何一方都能向?qū)Ψ桨l(fā)送數(shù)據(jù)和接收對(duì)方發(fā)來(lái)的數(shù)據(jù)。TCP協(xié)議負(fù)責(zé)把用戶數(shù)據(jù)(字節(jié)流)按一定的格式和長(zhǎng)度組成多個(gè)數(shù)據(jù)報(bào)進(jìn)行發(fā)送,并在接收到數(shù)據(jù)報(bào)之后按分解順序重新組裝和恢復(fù)用戶數(shù)據(jù)。
利用TCP傳輸數(shù)據(jù)時(shí),數(shù)據(jù)是以字節(jié)流的形式進(jìn)行傳輸?shù)摹?/p>

2.1.3 連接的終止

建立一個(gè)連接需要三次握手,而終止一個(gè)連接要經(jīng)過(guò)四次握手,這是由TCP的半關(guān)閉(half-close)造成的。具體過(guò)程如圖所示:

2.1.4 TCP的主要特點(diǎn)

TCP最主要的特點(diǎn)如下。
(1) 是面向連接的協(xié)議。
(2) 端到端的通信。每個(gè)TCP連接只能有兩個(gè)端點(diǎn),而且只能一對(duì)一通信,不能一點(diǎn)對(duì)多點(diǎn)直接通信。
(3) 高可靠性。通過(guò)TCP連接傳送的數(shù)據(jù),能保證數(shù)據(jù)無(wú)差錯(cuò)、不丟失、不重復(fù)地準(zhǔn)確到達(dá)接收方,并且保證各數(shù)據(jù)到達(dá)的順序與其發(fā)出的順序相同。
(4) 全雙工方式傳輸。
(5) 數(shù)據(jù)以字節(jié)流的方式傳輸。
(6) 傳輸?shù)臄?shù)據(jù)無(wú)消息邊界。

2.1.5 同步與異步

同步工作方式是指利用TCP編寫(xiě)的程序執(zhí)行到監(jiān)聽(tīng)或接收語(yǔ)句時(shí),在未完成工作(偵聽(tīng)到連接請(qǐng)求或收到對(duì)方發(fā)來(lái)的數(shù)據(jù))前不再繼續(xù)往下執(zhí)行,線程處于阻塞狀態(tài),直到該語(yǔ)句完成相應(yīng)的工作后才繼續(xù)執(zhí)行下一條語(yǔ)句。
異步工作方式是指程序執(zhí)行到監(jiān)聽(tīng)或接收語(yǔ)句時(shí),不論工作是否完成,都會(huì)繼續(xù)往下執(zhí)行。

2.2 UDP

UDP是一種簡(jiǎn)單的、面向數(shù)據(jù)報(bào)的無(wú)連接的協(xié)議,提供的是不一定可靠的傳輸服務(wù)。所謂“無(wú)連接”是指在正式通信前不必與對(duì)方先建立連接,不管對(duì)方狀態(tài)如何都直接發(fā)送過(guò)去。這與發(fā)手機(jī)短信非常相似,只要知道對(duì)方的手機(jī)號(hào)就可以了,不要考慮對(duì)方手機(jī)處于什么狀態(tài)。UDP雖然不能保證數(shù)據(jù)傳輸?shù)目煽啃裕珨?shù)據(jù)傳輸?shù)男瘦^高。

2.2.1 UDP與TCP的區(qū)別

(1) UDP可靠性不如TCP
TCP包含了專(zhuān)門(mén)的傳遞保證機(jī)制,當(dāng)數(shù)據(jù)接收方收到發(fā)送方傳來(lái)的信息時(shí),會(huì)自動(dòng)向發(fā)送方發(fā)出確認(rèn)消息;發(fā)送方只有在接收到該確認(rèn)消息之后才繼續(xù)傳送其他信息,否則將一直等待直到收到確認(rèn)信息為止。與TCP不同,UDP并不提供數(shù)據(jù)傳送的保證機(jī)制。如果在從發(fā)送方到接收方的傳遞過(guò)程中出現(xiàn)數(shù)據(jù)報(bào)的丟失,協(xié)議本身并不能做出任何檢測(cè)或提示。因此,通常人們把UDP稱(chēng)為不可靠的傳輸協(xié)議。
(2) UDP不能保證有序傳輸
UDP不能確保數(shù)據(jù)的發(fā)送和接收順序。對(duì)于突發(fā)性的數(shù)據(jù)報(bào),有可能會(huì)亂序。

2.2.2 UDP的優(yōu)勢(shì)

(1) UDP速度比TCP快
由于UDP不需要先與對(duì)方建立連接,也不需要傳輸確認(rèn),因此其數(shù)據(jù)傳輸速度比TCP快得多。對(duì)于強(qiáng)調(diào)傳輸性能而不是傳輸完整性的應(yīng)用(比如網(wǎng)絡(luò)音頻播放、視頻點(diǎn)播和網(wǎng)絡(luò)會(huì)議等),使用UDP比較合適,因?yàn)樗膫鬏斔俣瓤?,使通過(guò)網(wǎng)絡(luò)播放的視頻音質(zhì)好、畫(huà)面清晰。
(2) UDP有消息邊界
發(fā)送方UDP對(duì)應(yīng)用程序交下來(lái)的報(bào)文,在添加首部后就向下直接交付給IP層。既不拆分,也不合并,而是保留這些報(bào)文的邊界。使用UDP不需要考慮消息邊界問(wèn)題,這樣使得UDP編程相比TCP,在對(duì)接收到的數(shù)據(jù)的處理方面要方便的多。在程序員看來(lái),UDP套接字使用比TCP簡(jiǎn)單。UDP的這一特征也說(shuō)明了它是一種面向報(bào)文的傳輸協(xié)議。
(3) UDP可以一對(duì)多傳輸
由于傳輸數(shù)據(jù)不建立連接,也就不需要維護(hù)連接狀態(tài)(包括收發(fā)狀態(tài)等),因此一臺(tái)服務(wù)器可以同時(shí)向多個(gè)客戶端傳輸相同的消息。利用UDP可以使用廣播或組播的方式同時(shí)向子網(wǎng)上的所有客戶進(jìn)程發(fā)送消息,這一點(diǎn)也比TCP方便。
其中,速度快是UDP的首要優(yōu)勢(shì)
由于TCP協(xié)議中植入了各種安全保障功能,在實(shí)際執(zhí)行的過(guò)程中會(huì)占用大量的系統(tǒng)開(kāi)銷(xiāo),無(wú)疑使速度受到嚴(yán)重影響。反觀UDP,由于拋棄了信息可靠傳輸機(jī)制,將安全和排序等功能移交給上層應(yīng)用完成,極大地降低了執(zhí)行時(shí)間,使速度得到了保證。簡(jiǎn)而言之,UDP的“理念”就是“不顧一切,只為更快地發(fā)送數(shù)據(jù)”。

三:socket一般應(yīng)用模式:

四:SOCKET通信基本流程圖:

根據(jù)socket通信基本流程圖,總結(jié)通信的基本步驟:

服務(wù)器端:

第一步:創(chuàng)建一個(gè)用于監(jiān)聽(tīng)連接的Socket對(duì)像;

第二步:用指定的端口號(hào)和服務(wù)器的ip建立一個(gè)EndPoint對(duì)像;

第三步:用socket對(duì)像的Bind()方法綁定EndPoint;

第四步:用socket對(duì)像的Listen()方法開(kāi)始監(jiān)聽(tīng);

第五步:接收到客戶端的連接,用socket對(duì)像的Accept()方法創(chuàng)建一個(gè)新的用于和客戶端進(jìn)行通信的socket對(duì)像;

第六步:通信結(jié)束后一定記得關(guān)閉socket;

客戶端:

第一步:建立一個(gè)Socket對(duì)像;

第二步:用指定的端口號(hào)和服務(wù)器的ip建立一個(gè)EndPoint對(duì)像;

第三步:用socket對(duì)像的Connect()方法以上面建立的EndPoint對(duì)像做為參數(shù),向服務(wù)器發(fā)出連接請(qǐng)求;

第四步:如果連接成功,就用socket對(duì)像的Send()方法向服務(wù)器發(fā)送信息;

第五步:用socket對(duì)像的Receive()方法接受服務(wù)器發(fā)來(lái)的信息 ;

第六步:通信結(jié)束后一定記得關(guān)閉socket;

五:示例程序

服務(wù)端界面:

代碼實(shí)現(xiàn)如下:

 using System;
 using System.Collections.Generic;
 using System.ComponentModel;
 using System.Data;
 using System.Drawing;
 using System.Linq;
 using System.Net;
 using System.Net.Sockets;
 using System.Text;
 using System.Threading.Tasks;
 using System.Windows.Forms;
 using System.Threading;
 using System.IO;
 
 namespace SocketServer
 {
     public partial class FrmServer : Form
     {
         public FrmServer()
         {
             InitializeComponent();
         }
 
         //定義回調(diào):解決跨線程訪問(wèn)問(wèn)題
         private delegate void SetTextValueCallBack(string strValue);
         //定義接收客戶端發(fā)送消息的回調(diào)
         private delegate void ReceiveMsgCallBack(string strReceive);
         //聲明回調(diào)
         private SetTextValueCallBack setCallBack;
         //聲明
         private ReceiveMsgCallBack receiveCallBack;
         //定義回調(diào):給ComboBox控件添加元素
         private delegate void SetCmbCallBack(string strItem);
         //聲明
         private SetCmbCallBack setCmbCallBack;
         //定義發(fā)送文件的回調(diào)
         private delegate void SendFileCallBack(byte[] bf);
         //聲明
         private SendFileCallBack sendCallBack;
 
         //用于通信的Socket
         Socket socketSend;
         //用于監(jiān)聽(tīng)的SOCKET
         Socket socketWatch;
 
         //將遠(yuǎn)程連接的客戶端的IP地址和Socket存入集合中
         Dictionary<string, Socket> dicSocket = new Dictionary<string, Socket>();
 
         //創(chuàng)建監(jiān)聽(tīng)連接的線程
         Thread AcceptSocketThread;
         //接收客戶端發(fā)送消息的線程
         Thread threadReceive;
 
         /// <summary>
         /// 開(kāi)始監(jiān)聽(tīng)
         /// </summary>
         /// <param name="sender"></param>
         /// <param name="e"></param>
         private void btn_Start_Click(object sender, EventArgs e)
         {
             //當(dāng)點(diǎn)擊開(kāi)始監(jiān)聽(tīng)的時(shí)候 在服務(wù)器端創(chuàng)建一個(gè)負(fù)責(zé)監(jiān)聽(tīng)I(yíng)P地址和端口號(hào)的Socket
             socketWatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
             //獲取ip地址
             IPAddress ip=IPAddress.Parse(this.txt_IP.Text.Trim());
             //創(chuàng)建端口號(hào)
             IPEndPoint point=new IPEndPoint(ip,Convert.ToInt32(this.txt_Port.Text.Trim()));
             //綁定IP地址和端口號(hào)
             socketWatch.Bind(point);
             this.txt_Log.AppendText("監(jiān)聽(tīng)成功"+" \r \n");
             //開(kāi)始監(jiān)聽(tīng):設(shè)置最大可以同時(shí)連接多少個(gè)請(qǐng)求
             socketWatch.Listen(10);
 
             //實(shí)例化回調(diào)
             setCallBack = new SetTextValueCallBack(SetTextValue);
             receiveCallBack = new ReceiveMsgCallBack(ReceiveMsg);
             setCmbCallBack = new SetCmbCallBack(AddCmbItem);
             sendCallBack = new SendFileCallBack(SendFile);
 
             //創(chuàng)建線程
             AcceptSocketThread = new Thread(new ParameterizedThreadStart(StartListen));
             AcceptSocketThread.IsBackground = true;
             AcceptSocketThread.Start(socketWatch);
         }
 
         /// <summary>
         /// 等待客戶端的連接,并且創(chuàng)建與之通信用的Socket
         /// </summary>
         /// <param name="obj"></param>
         private void StartListen(object obj)
         {
             Socket socketWatch = obj as Socket;
             while (true)
             {               
                 //等待客戶端的連接,并且創(chuàng)建一個(gè)用于通信的Socket
                 socketSend = socketWatch.Accept();
                 //獲取遠(yuǎn)程主機(jī)的ip地址和端口號(hào)
                 string strIp=socketSend.RemoteEndPoint.ToString();
                 dicSocket.Add(strIp, socketSend);
                 this.cmb_Socket.Invoke(setCmbCallBack, strIp);
                 string strMsg = "遠(yuǎn)程主機(jī):" + socketSend.RemoteEndPoint + "連接成功";
                 //使用回調(diào)
                 txt_Log.Invoke(setCallBack, strMsg);
 
                 //定義接收客戶端消息的線程
                 Thread threadReceive = new Thread(new ParameterizedThreadStart(Receive));
                 threadReceive.IsBackground = true;
                 threadReceive.Start(socketSend);
 
             }
         }
 
        
 
         /// <summary>
         /// 服務(wù)器端不停的接收客戶端發(fā)送的消息
         /// </summary>
         /// <param name="obj"></param>
         private void Receive(object obj)
         {
             Socket socketSend = obj as Socket;
             while (true)
             {
                 //客戶端連接成功后,服務(wù)器接收客戶端發(fā)送的消息
                 byte[] buffer = new byte[2048];
                 //實(shí)際接收到的有效字節(jié)數(shù)
                 int count = socketSend.Receive(buffer);
                 if (count == 0)//count 表示客戶端關(guān)閉,要退出循環(huán)
                 {
                     break;
                 }
                 else
                 {
                     string str = Encoding.Default.GetString(buffer, 0, count);
                     string strReceiveMsg = "接收:" + socketSend.RemoteEndPoint + "發(fā)送的消息:" + str;
                     txt_Log.Invoke(receiveCallBack, strReceiveMsg);
                 }
             }
         }
 
         /// <summary>
         /// 回調(diào)委托需要執(zhí)行的方法
         /// </summary>
         /// <param name="strValue"></param>
         private void SetTextValue(string strValue)
         {
             this.txt_Log.AppendText(strValue + " \r \n");
         }
 
 
         private void ReceiveMsg(string strMsg)
         {
             this.txt_Log.AppendText(strMsg + " \r \n");
         }
 
         private void AddCmbItem(string strItem)
         {
             this.cmb_Socket.Items.Add(strItem);
         }
 
         /// <summary>
         /// 服務(wù)器給客戶端發(fā)送消息
         /// </summary>
         /// <param name="sender"></param>
         /// <param name="e"></param>
         private void btn_Send_Click(object sender, EventArgs e)
         {
             try
             {
                 string strMsg = this.txt_Msg.Text.Trim();
                 byte[] buffer = Encoding.Default.GetBytes(strMsg);
                 List<byte> list = new List<byte>();
                 list.Add(0);
                 list.AddRange(buffer);
                 //將泛型集合轉(zhuǎn)換為數(shù)組
                 byte[] newBuffer = list.ToArray();
                 //獲得用戶選擇的IP地址
                 string ip = this.cmb_Socket.SelectedItem.ToString();
                 dicSocket[ip].Send(newBuffer);
             }
             catch (Exception ex)
             {
                 MessageBox.Show("給客戶端發(fā)送消息出錯(cuò):"+ex.Message);
             }
             //socketSend.Send(buffer);
         }
 
         /// <summary>
         /// 選擇要發(fā)送的文件
         /// </summary>
         /// <param name="sender"></param>
         /// <param name="e"></param>
         private void btn_Select_Click(object sender, EventArgs e)
         {
             OpenFileDialog dia = new OpenFileDialog();
             //設(shè)置初始目錄
             dia.InitialDirectory = @"";
             dia.Title = "請(qǐng)選擇要發(fā)送的文件";
             //過(guò)濾文件類(lèi)型
             dia.Filter = "所有文件|*.*";
             dia.ShowDialog();
             //將選擇的文件的全路徑賦值給文本框
             this.txt_FilePath.Text = dia.FileName;
         }
 
         /// <summary>
         /// 發(fā)送文件
         /// </summary>
         /// <param name="sender"></param>
         /// <param name="e"></param>
         private void btn_SendFile_Click(object sender, EventArgs e)
         {
             List<byte> list = new List<byte>();
             //獲取要發(fā)送的文件的路徑
             string strPath = this.txt_FilePath.Text.Trim();
             using (FileStream sw = new FileStream(strPath,FileMode.Open,FileAccess.Read))
             {
                 byte[] buffer = new byte[2048];
                 int r = sw.Read(buffer, 0, buffer.Length);
                 list.Add(1);
                 list.AddRange(buffer);
 
                 byte[] newBuffer = list.ToArray();
                 //發(fā)送
                 //dicSocket[cmb_Socket.SelectedItem.ToString()].Send(newBuffer, 0, r+1, SocketFlags.None);
                 btn_SendFile.Invoke(sendCallBack, newBuffer);
 
                 
             }
             
         }
 
         private void SendFile(byte[] sendBuffer)
         {
 
             try
             {
                 dicSocket[cmb_Socket.SelectedItem.ToString()].Send(sendBuffer, SocketFlags.None);
             }
             catch (Exception ex)
             {
                 MessageBox.Show("發(fā)送文件出錯(cuò):"+ex.Message);
             }
         }
 
         private void btn_Shock_Click(object sender, EventArgs e)
         {
             byte[] buffer = new byte[1] { 2};
             dicSocket[cmb_Socket.SelectedItem.ToString()].Send(buffer);
         }
 
         /// <summary>
         /// 停止監(jiān)聽(tīng)
         /// </summary>
         /// <param name="sender"></param>
         /// <param name="e"></param>
         private void btn_StopListen_Click(object sender, EventArgs e)
         {
             socketWatch.Close();
             socketSend.Close();
             //終止線程
             AcceptSocketThread.Abort();
             threadReceive.Abort();
         }
     }
 }

客戶端界面

代碼實(shí)現(xiàn)如下:

 using System;
 using System.Collections.Generic;
 using System.ComponentModel;
 using System.Data;
 using System.Drawing;
 using System.Linq;
 using System.Text;
 using System.Threading.Tasks;
 using System.Windows.Forms;
 using System.Net.Sockets;
 using System.Net;
 using System.Threading;
 using System.IO;
 
 namespace SocketClient
 {
     public partial class FrmClient : Form
     {
         public FrmClient()
         {
             InitializeComponent();
         }
 
         //定義回調(diào)
         private delegate void SetTextCallBack(string strValue);
         //聲明
         private SetTextCallBack setCallBack;
 
         //定義接收服務(wù)端發(fā)送消息的回調(diào)
         private delegate void ReceiveMsgCallBack(string strMsg);
         //聲明
         private ReceiveMsgCallBack receiveCallBack;
 
         //創(chuàng)建連接的Socket
         Socket socketSend;
         //創(chuàng)建接收客戶端發(fā)送消息的線程
         Thread threadReceive;
 
         /// <summary>
         /// 連接
         /// </summary>
         /// <param name="sender"></param>
         /// <param name="e"></param>
         private void btn_Connect_Click(object sender, EventArgs e)
         {
             try
             {
                 socketSend = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                 IPAddress ip = IPAddress.Parse(this.txt_IP.Text.Trim());
                 socketSend.Connect(ip, Convert.ToInt32(this.txt_Port.Text.Trim()));
                 //實(shí)例化回調(diào)
                 setCallBack = new SetTextCallBack(SetValue);
                 receiveCallBack = new ReceiveMsgCallBack(SetValue);
                 this.txt_Log.Invoke(setCallBack, "連接成功");
 
                 //開(kāi)啟一個(gè)新的線程不停的接收服務(wù)器發(fā)送消息的線程
                 threadReceive = new Thread(new ThreadStart(Receive));
                 //設(shè)置為后臺(tái)線程
                 threadReceive.IsBackground = true;
                 threadReceive.Start();
             }
             catch (Exception ex)
             {
                 MessageBox.Show("連接服務(wù)端出錯(cuò):" + ex.ToString());
             }
         }
 
         /// <summary>
         /// 接口服務(wù)器發(fā)送的消息
         /// </summary>
         private void Receive()
         {
             try
             {
                 while (true)
                 {
                     byte[] buffer = new byte[2048];
                     //實(shí)際接收到的字節(jié)數(shù)
                     int r = socketSend.Receive(buffer);
                     if (r == 0)
                     {
                         break;
                     }
                     else
                     {
                         //判斷發(fā)送的數(shù)據(jù)的類(lèi)型
                         if (buffer[0] == 0)//表示發(fā)送的是文字消息
                         {
                             string str = Encoding.Default.GetString(buffer, 1, r - 1);
                             this.txt_Log.Invoke(receiveCallBack, "接收遠(yuǎn)程服務(wù)器:" + socketSend.RemoteEndPoint + "發(fā)送的消息:" + str);
                         }
                         //表示發(fā)送的是文件
                         if (buffer[0] == 1)
                         {
                             SaveFileDialog sfd = new SaveFileDialog();
                             sfd.InitialDirectory = @"";
                             sfd.Title = "請(qǐng)選擇要保存的文件";
                             sfd.Filter = "所有文件|*.*";
                             sfd.ShowDialog(this);
 
                             string strPath = sfd.FileName;
                             using (FileStream fsWrite = new FileStream(strPath, FileMode.OpenOrCreate, FileAccess.Write))
                             {
                                 fsWrite.Write(buffer, 1, r - 1);
                             }
 
                             MessageBox.Show("保存文件成功");
                         }
                     }
 
 
                 }
             }
             catch (Exception ex)
             {
                 MessageBox.Show("接收服務(wù)端發(fā)送的消息出錯(cuò):" + ex.ToString());
             }
         }
 
 
         private void SetValue(string strValue)
         {
             this.txt_Log.AppendText(strValue + "\r \n");
         }
 
         /// <summary>
         /// 客戶端給服務(wù)器發(fā)送消息
         /// </summary>
         /// <param name="sender"></param>
         /// <param name="e"></param>
         private void btn_Send_Click(object sender, EventArgs e)
         {
             try
             {
                 string strMsg = this.txt_Msg.Text.Trim();
                 byte[] buffer = new byte[2048];
                 buffer = Encoding.Default.GetBytes(strMsg);
                 int receive = socketSend.Send(buffer);
             }
             catch (Exception ex)
             {
                 MessageBox.Show("發(fā)送消息出錯(cuò):" + ex.Message);
             }
         }
 
         private void FrmClient_Load(object sender, EventArgs e)
         {
             Control.CheckForIllegalCrossThreadCalls = false;
         }
 
         /// <summary>
         /// 斷開(kāi)連接
         /// </summary>
         /// <param name="sender"></param>
         /// <param name="e"></param>
         private void btn_CloseConnect_Click(object sender, EventArgs e)
         {
             //關(guān)閉socket
             socketSend.Close();
             //終止線程
             threadReceive.Abort();
         }
     }
 }

到此這篇關(guān)于C#網(wǎng)絡(luò)編程之Socket編程的文章就介紹到這了。希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • C# 實(shí)現(xiàn)簡(jiǎn)易的串口監(jiān)視上位機(jī)功能附源碼下載

    C# 實(shí)現(xiàn)簡(jiǎn)易的串口監(jiān)視上位機(jī)功能附源碼下載

    這篇文章主要介紹了C# 實(shí)現(xiàn)簡(jiǎn)易的串口監(jiān)視上位機(jī)功能,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-11-11
  • C#強(qiáng)制類(lèi)型轉(zhuǎn)換小結(jié)

    C#強(qiáng)制類(lèi)型轉(zhuǎn)換小結(jié)

    任何一門(mén)編程語(yǔ)言均有相關(guān)數(shù)據(jù)類(lèi)型。C#也不例外,不過(guò)轉(zhuǎn)換過(guò)程要注意小類(lèi)型能轉(zhuǎn)換成大類(lèi)型,但大類(lèi)型一般不能轉(zhuǎn)換成小類(lèi)型,下面小編給大家詳解C#強(qiáng)制類(lèi)型轉(zhuǎn)換小結(jié),需要的朋友參考下吧
    2017-07-07
  • C#調(diào)用動(dòng)態(tài)庫(kù)

    C#調(diào)用動(dòng)態(tài)庫(kù)

    本文詳細(xì)講解了C#調(diào)用動(dòng)態(tài)庫(kù)的方法,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-05-05
  • C#如何更改Word的語(yǔ)言設(shè)置

    C#如何更改Word的語(yǔ)言設(shè)置

    這篇文章主要為大家詳細(xì)介紹了C#如何更改Word的語(yǔ)言設(shè)置,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-05-05
  • C#為配置文件加密的實(shí)現(xiàn)方法

    C#為配置文件加密的實(shí)現(xiàn)方法

    這篇文章主要介紹了C#為配置文件加密的實(shí)現(xiàn)方法,可實(shí)現(xiàn)對(duì)配置文件中的敏感信息進(jìn)行加密,非常具有實(shí)用價(jià)值,需要的朋友可以參考下
    2014-10-10
  • 深入理解c#多態(tài)

    深入理解c#多態(tài)

    這篇文章主要介紹了c#多態(tài)的相關(guān)知識(shí),文中代碼非常詳細(xì),幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下
    2020-06-06
  • Entity?Framework配置關(guān)系

    Entity?Framework配置關(guān)系

    這篇文章介紹了Entity?Framework配置關(guān)系的方法,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-06-06
  • C#實(shí)現(xiàn)redis讀寫(xiě)的方法

    C#實(shí)現(xiàn)redis讀寫(xiě)的方法

    這篇文章主要為大家詳細(xì)介紹了C#實(shí)現(xiàn)redis讀寫(xiě)的方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-05-05
  • 淺談C# 9.0 新特性之只讀屬性和記錄

    淺談C# 9.0 新特性之只讀屬性和記錄

    這篇文章主要介紹了C# 9.0 新特性之只讀屬性和記錄的的相關(guān)資料,文中講解非常細(xì)致,代碼幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以參考下
    2020-06-06
  • c#基礎(chǔ)系列之ref和out的深入理解

    c#基礎(chǔ)系列之ref和out的深入理解

    有過(guò)C#基礎(chǔ)知識(shí)的都應(yīng)該清楚Ref和Out的使用方法,所以下面這篇文章主要給大家介紹了關(guān)于c#基礎(chǔ)系列之ref和out的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友可以參考借鑒,下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2018-09-09

最新評(píng)論