c#实现Socket网络编程
命名空間:
在網絡環境下,我們最感興趣的兩個命名空間是System.Net和?System.Net.Sockets。
System.Net命名空間通常與較高程的操作有關,例如download或upload,試用HTTP和其他協議進行Web請求等等
System.Net.Sockets命名空間所包含的類通常與較低程的操作有關。如果要直接使用Sockets或者?TCP/IP之類的協議
?
Socket對象創建:
針對Socket編程,.NET?框架的?Socket?類是?Winsock32?API?提供的套接字服務的托管代碼版本。Socket可以象流Stream一樣被視為一個數據通道,這個通道架設在應用程序端(客戶端)和遠程服務器端之間,而后,數據的讀取(接收)和寫入(發送)均針對這個通道來進行。
Socket?類支持兩種基本模式:同步和異步。其區別在于:在同步模式中,對執行網絡操作的函數(如?Send?和?Receive)的調用一直等到操作完成后才將控制返回給調用程序。在異步模式中,這些調用立即返回。?
?
在使用之前,你需要首先創建Socket對象的實例,這可以通過Socket類的構造方法來實現:?
public?Socket(AddressFamily?addressFamily,SocketType?socketType,ProtocolType?protocolType);?
其中,addressFamily?參數指定?Socket?使用的尋址方案,socketType?參數指定?Socket?的類型,protocolType?參數指定?Socket?使用的協議。?
下面的示例語句創建一個?Socket,它可用于在基于?TCP/IP?的網絡(如?Internet)上通訊。?
Socket?temp?=?new?Socket(AddressFamily.InterNetwork,?SocketType.Stream,?ProtocolType.Tcp);?
若要使用?UDP?而不是?TCP,需要更改協議類型,如下面的示例所示:?
Socket?temp?=?new?Socket(AddressFamily.InterNetwork,?SocketType.Dgram,?ProtocolType.Udp);?
一旦創建?Socket,在客戶端,你將可以通過Connect方法連接到指定的服務器,并通過Send/SendTo
?
Socket操作流程:
方法向遠程服務器發送數據,而后可以通過?Receive/ReceiveFrom從服務端接收數據;而在服務器端,你需要使用Bind方法綁定所指定的接口使Socket與一個本地終結點相聯,并通過Listen方法偵聽該接口上的請求,當偵聽到用戶端的連接時,調用Accept完成連接的操作,創建新的Socket以處理傳入的連接請求。使用完?Socket?后,記住使用?Shutdown?方法禁用?Socket,并使用?Close?方法關閉?Socket。
?
終結點:
在Internet中,TCP/IP?使用套接字(一個網絡地址和一個服務端口號)來唯一標識設備。網絡地址(IP)標識網絡上的特定設備;端口號(Port)標識要連接到的該設備上的特定服務。網絡地址和服務端口的組合稱為終結點,在?.NET?框架中正是由?EndPoint?類表示這個終結點,它提供表示網絡資源或服務的抽象,用以標志網絡地址等信息。
.Net同時也為每個受支持的地址族定義了?EndPoint?的子代;對于?IP?地址族,該類為?IPEndPoint。IPEndPoint?類包含應用程序連接到主機上的服務所需的主機和端口信息。
?
IP地址獲取方式:
用到IPEndPoint類的時候就不可避免地涉及到計算機IP地址,System.Net命名空間中有兩種類可以得到IP地址實例:?
IPAddress類:?在同一局域網中采用的獲取方式。?IPAddress?類包含計算機在?IP?網絡上的地址。其Parse方法可將?IP?地址字符串轉換為?IPAddress?實例。下面的語句創建一個?IPAddress?實例:?
IPAddress?myIP?=?IPAddress.Parse("192.168.0.1");?
Dns?類:??在互聯網中采用的獲取方式。?向使用?TCP/IP?Internet?服務的應用程序提供域名服務。其Resolve?方法查詢?DNS?服務器以將用戶友好的域名(如"host.mydomain.com")映射到數字形式的?Internet?地址(如?192.168.0.1)。
Resolve方法?返回一個?IPHostEnty?實例,該實例包含所請求名稱的地址和別名的列表。大多數情況下,可以使用?AddressList?數組中返回的第一個地址。下面的代碼獲取一個?IPAddress?實例,該實例包含服務器?host.mydomain.com?的?IP?地址。?
IPHostEntry?ipHostInfo?=?Dns.Resolve("host.mydomain.com?");?
IPAddress?ipAddress?=?ipHostInfo.AddressList[0];?
你也可以使用GetHostName方法得到IPHostEntry實例:?
IPHosntEntry?hostInfo=Dns.GetHostByName("host.mydomain.com?")?
在使用以上方法時,你將可能需要處理以下幾種異常:?
SocketException異常:訪問Socket時操作系統發生錯誤引發?
ArgumentNullException異常:參數為空引用引發?
ObjectDisposedException異常:Socket已經關閉引發
?
通信過程示例:
?
服務器端:
?
服務器端接收客戶端數據步驟:
?
?
?
public class CM{public static bool ISAddSocekt = true;//現在是否繼續接收新的客戶端連接public static int AddressIndex = 0;//這是當前與服務器端連接的第幾個客戶端 //病歷號和客戶端IP關聯表(key:病歷號 value:客戶端的IP地址,不包含port)public static Dictionary<string, string> dic_Patient_IP = new Dictionary<string, string>();//客戶端IP和客戶端連接順序關聯表(key:病歷號 value:客戶端的IP地址,不包含port)public static Dictionary<string, int> dic_IP_Index = new Dictionary<string, int>();//客戶端集合 key:客戶端IP地址,Value:客戶端實體public static Dictionary<string, Socket> dic_IP_Socket = new Dictionary<string, Socket>();private delegate void AcceptDelegete();private delegate void ReadDelegete(Socket s);public static int ServerPort = 2000;//服務器端端口public static Socket serverSocket;//服務器端 //用20個線程分別接受一個設備的數據public static int ClientCount_Max = 20;//客戶端的最大數量public static void Listen(){AcceptDelegete listen = AcceptConnection;IAsyncResult asy = listen.BeginInvoke(null, null);}private static void AcceptConnection(){try{serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);IPEndPoint localEP = new IPEndPoint(IPAddress.Any, ServerPort);//將socket綁定到本地的終結點上 serverSocket.Bind(localEP);//開始監聽 serverSocket.Listen(ClientCount_Max);serverSocket.BeginAccept(new AsyncCallback(AcceptCallBack), null);}catch (Exception ex){}}private static void AcceptCallBack(IAsyncResult iar){try{while (ISAddSocekt){// 調用EndAccept完成BeginAccept異步調用,返回一個新的Socket處理與客戶的通信Socket clientSocket = serverSocket.EndAccept(iar);IPEndPoint clientPoint = clientSocket.RemoteEndPoint as IPEndPoint;if (!dic_IP_Index.ContainsKey(clientPoint.Address.ToString())){dic_IP_Index.Add(clientPoint.Address.ToString(), AddressIndex);AddressIndex += 1;//去除舊的客戶端實體 dic_IP_Socket.Remove(clientPoint.Address.ToString());}dic_IP_Socket.Add(clientPoint.Address.ToString(), clientSocket);//開啟新線程讀取數據CM_Data client = new CM_Data(clientSocket);Thread thClient = new Thread(new ThreadStart(client.ClientServer));thClient.Start();//在達到多大的客戶端連接限制前,繼續監聽是否有新的客戶端連接if (dic_IP_Index.Count < ClientCount_Max){serverSocket.BeginAccept(new AsyncCallback(AcceptCallBack), null);}}}catch (Exception ex){}}}//在新線程中不同的循環接收客戶端發送過來的數據信息// CM_Data類里的代碼public class CM_Data{Encoding encoding = Encoding.GetEncoding("GB2312"); //解碼器(可以用于漢字)private Socket client;//當前與服務器端通信的客戶端實體private byte[] receiveBytes = new byte[1024];//服務器端設置緩沖區private int recCount;byte[] byte_Data;//傳遞連接socketpublic CM_Data(Socket ClientSocket){this.client = ClientSocket;}public void ClientServer(){try{while (true){recCount = client.Receive(receiveBytes, receiveBytes.Length, 0);//從客戶端接收信息,recCount為有效數據的個數if (recCount != 0)//當服務器端的緩沖區接收到的信息不為空時 {byte_Data = new byte[recCount];for (int i = 0; i < recCount; i++){byte_Data[i] = receiveBytes[i];}//獲取數據后的數據處理 DataRead(byte_Data);}else{break;}}}catch (Exception ex){MessageBox.Show("數據接收時發生錯誤:"+ex.Message);}client.Close();} 服務器端接收客戶端數據?
?
服務器端向客戶端發送數據:
?
客戶端:
項目的客戶端代碼是否下位機完成的(使用C++代碼),下面的客戶端示例,是我在測試程序中使用到的c#版本的代碼示例。
客戶端接收服務器端數據步驟:
?
?
轉載于:https://www.cnblogs.com/eye-like/p/3993435.html
總結
以上是生活随笔為你收集整理的c#实现Socket网络编程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: STL之Iterator(迭代器)
- 下一篇: Arch linux