C#中的Socket編程詳解
文章按照 Socket 的 創(chuàng)建、連接、傳輸數(shù)據(jù)、釋放資源的過(guò)程來(lái)寫(xiě)。給出方法、參數(shù)的詳細(xì)信息。
一,網(wǎng)絡(luò)基礎(chǔ)
說(shuō)到 Socket,需要學(xué)習(xí)一下TCP/IP的知識(shí),了解一下OSI 網(wǎng)絡(luò)模。
推薦別人的文章,可以很快地了解這些。
http://www.dbjr.com.cn/article/234633.htm
http://www.dbjr.com.cn/article/234653.htm
二,Socket 對(duì)象
無(wú)論是服務(wù)器還是客戶端,都要?jiǎng)?chuàng)建一個(gè) SOCKET 對(duì)象,創(chuàng)建方法一致。
以下是常見(jiàn)的Socket對(duì)象創(chuàng)建實(shí)例
Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); //監(jiān)控 ip4 地址,套接字類型為 TCP ,協(xié)議類型為 TCP
其有三個(gè)構(gòu)造函數(shù)
public Socket(SocketInformation socketInformation);
public Socket(SocketType socketType, ProtocolType protocolType);
public Socket(AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType);
第一個(gè)構(gòu)造函數(shù),SocketInformation 對(duì)象保存的是
Socket(SocketType, ProtocolType)
實(shí)質(zhì)上跟第二個(gè)構(gòu)造函數(shù)是一樣的。就好像你可以直接把( 一個(gè)蘋(píng)果 , 一個(gè)梨)直接放進(jìn)籃子,也可以先給 水果包裝好 再放進(jìn)籃子里。
下面將解釋所有參數(shù)的意義。
SocketType
指定 Socket 類的實(shí)例表示的套接字類型。
TCP 用主機(jī)的IP地址加上主機(jī)上的端口號(hào)作為 TCP 連接的端點(diǎn),這種端點(diǎn)就叫做套接字(socket)或插口。 套接字用(IP地址:端口號(hào))表示。
SocketType 是enum 類型,其字段如下
SocketType | 值 | 對(duì)應(yīng)的ProtocolType | 描述 |
---|---|---|---|
Unknown | -1 | Unknown | 指定未知的 Socket 類型。 |
Stream(使用字節(jié)流) | 1 | Tcp | 支持可靠、雙向、基于連接的字節(jié)流 |
Dgram(使用數(shù)據(jù)報(bào)) | 2 | Udp | 面向無(wú)連接 |
Raw | 3 | Icmp、lgmp | 支持對(duì)基礎(chǔ)傳輸協(xié)議的訪問(wèn) |
Rdm | 4 |
| 支持無(wú)連接、面向消息、以可靠方式發(fā)送的消息, 并保留數(shù)據(jù)中的消息邊界 |
Seqpacket | 5 | 在網(wǎng)絡(luò)上提供排序字節(jié)流的面向連接且可靠的雙向傳輸 |
如需了解更詳細(xì)的資料,請(qǐng)查閱Microsoft文檔
地址:https://docs.microsoft.com/zh-cn/dotnet/api/system.net.sockets.sockettype?view=netframework-4.7.2
ProtocolType
表示協(xié)議類型,是一個(gè)enum 類型。
其所有字段如下
SocketType | 值 | 對(duì)應(yīng)的ProtocolType | 描述 |
---|---|---|---|
Unknown | -1 | Unknown | 指定未知的 Socket 類型。 |
Stream(使用字節(jié)流) | 1 | Tcp | 支持可靠、雙向、基于連接的字節(jié)流 |
Dgram(使用數(shù)據(jù)報(bào)) | 2 | Udp | 面向無(wú)連接 |
Raw | 3 | Icmp、lgmp | 支持對(duì)基礎(chǔ)傳輸協(xié)議的訪問(wèn) |
Rdm | 4 |
| 支持無(wú)連接、面向消息、以可靠方式發(fā)送的消息, 并保留數(shù)據(jù)中的消息邊界 |
Seqpacket | 5 | 在網(wǎng)絡(luò)上提供排序字節(jié)流的面向連接且可靠的雙向傳輸 |
AddressFamily
表示使用的網(wǎng)絡(luò)尋址方案,是一個(gè) enum 類型。
地址類型 | 值 | 描述 |
---|---|---|
AppleTalk | 16 | AppleTalk 地址。 |
Atm | 22 | 本機(jī) ATM 服務(wù)地址。 |
Banyan | 21 | Banyan 地址。 |
Ccitt | 10 | CCITT 協(xié)議(如 X.25)的地址。 |
Chaos | 5 | MIT CHAOS 協(xié)議的地址。 |
Cluster | 24 | Microsoft 群集產(chǎn)品的地址。 |
DataKit | 9 | Datakit 協(xié)議的地址。 |
DataLink | 13 | 直接數(shù)據(jù)鏈接接口地址。 |
DecNet | 12 | DECnet 地址。 |
Ecma | 8 | 歐洲計(jì)算機(jī)制造商協(xié)會(huì) (ECMA) 地址。 |
FireFox | 19 | FireFox 地址。 |
HyperChannel | 15 | NSC Hyperchannel 地址。 |
Ieee12844 | 25 | IEEE 1284.4 工作組地址。 |
ImpLink | 3 | ARPANET IMP 地址。 |
InterNetwork | 2 | IP 版本 4 的地址。 |
InterNetworkV6 | 23 | IP 版本 6 的地址。 |
Ipx | 6 | IPX 或 SPX 地址。 |
Irda | 26 | IrDA 地址。 |
Iso | 7 | ISO 協(xié)議的地址。 |
Lat | 14 | LAT 地址。 |
Max | 29 | MAX 地址。 |
NetBios | 17 | NetBios 地址。 |
NetworkDesigners | 28 | 支持網(wǎng)絡(luò)設(shè)計(jì)器 OSI 網(wǎng)關(guān)的協(xié)議的地址。 |
NS | 6 | Xerox NS 協(xié)議的地址。 |
Osi | 7 | OSI 協(xié)議的地址。 |
Pup | 4 | PUP 協(xié)議的地址。 |
Sna | 11 | IBM SNA 地址。 |
Unix | 1 | Unix 本地到主機(jī)地址。 |
Unknown | -1 | 未知的地址族。 |
Unspecified | 0 | 未指定的地址族。 |
VoiceView | 18 | VoiceView 地址。 |
Socket 官方文檔地址
三,Bind() 綁定與 Connect() 連接
Bind() 用于綁定IPEndPoint 對(duì)象,在服務(wù)端使用。
Connect() 在客戶端使用,用于連接服務(wù)端。
創(chuàng)建 Socket 對(duì)象后,接著綁定本地Socket / 連接服務(wù)端。
Bind()
public void Bind (System.Net.EndPoint localEP);
使用方法
Socket serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); IPAddress iP = IPAddress.Parse("127.0.0.1"); //上面不重要,看下面 //IPEndPoint iPEndPoint = new IPEndPoint(iP, 2300); //serverSocket.Bind(iPEndPoint); serverSocket.Bind(new IPEndPoint(iP, 2300))
你將在在本地創(chuàng)建IPEndPoint 對(duì)象,擁有此 ip:post 的訪問(wèn)權(quán)限。目的是綁定本地機(jī)器的某個(gè)端口,所有經(jīng)過(guò)此端口的數(shù)據(jù)就歸你管了。
Connect()
與遠(yuǎn)程主機(jī)建立連接。Connect() 有四個(gè)重載方法,不必關(guān)注,只需知道,必需提供 IP 和 Post 兩個(gè)值。
使用方法
IPAddress iP = IPAddress.Parse("127.0.0.1"); IPEndPoint iPEndPoint = new IPEndPoint(iP, 2300); Socket serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); //創(chuàng)建與遠(yuǎn)程主機(jī)的連接 serverSocket.Connect(iPEndPoint);
四,Listen() 監(jiān)聽(tīng)請(qǐng)求連接 和 Accept() 接收連接請(qǐng)求
Listen()
監(jiān)控所有發(fā)送到此主機(jī)的、特點(diǎn)端口的連接請(qǐng)求。服務(wù)端使用,客戶端不需要。
public void Listen (int backlog);
使用 Bind() 后,使用 Listen() 方法進(jìn)行監(jiān)控,backlog 參數(shù)指定可排隊(duì)等待接受的傳入連接的數(shù)量,即掛起的連接隊(duì)列的最大長(zhǎng)度。
示例
serverSocket.Listen(10); //開(kāi)始監(jiān)聽(tīng)
Accept()
Accept() 以同步方式監(jiān)聽(tīng)套接字,在連接請(qǐng)求隊(duì)列中提取第一個(gè)掛起的連接請(qǐng)求,然后創(chuàng)建并返回一個(gè)新的 Socket 對(duì)象。
代碼示例
//創(chuàng)建終結(jié)點(diǎn)(EndPoint) IPAddress ip = IPAddress.Any; IPEndPoint ipe = new IPEndPoint(ip, 8000); //創(chuàng)建 socket 并開(kāi)始監(jiān)聽(tīng) Socket serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); serverSocket.Bind(ipe); serverSocket.Listen(10);//開(kāi)始監(jiān)聽(tīng) //接受到client連接,為此連接建立新的socket,并接受信息 Socket temp = serverSocket.Accept();//為新建連接創(chuàng)建新的socket
//關(guān)閉連接 temp.Close();
注意的是,每次建立連接是一個(gè) Accept() 對(duì)象,如果你要進(jìn)行 服務(wù)器-客戶端互相通訊,應(yīng)使用同一個(gè) Accept() 對(duì)象。每個(gè) Accept 對(duì)象都是 從客戶端請(qǐng)求建立開(kāi)始的,期間只要使用同一個(gè) Accept 對(duì)象,都可以進(jìn)行數(shù)據(jù)傳輸。
五,Receive() 與 Send()
- Receive() 接收信息
- Send() 發(fā)送信息
在服務(wù)端和客戶端都使用這兩個(gè)方法。
Receive()
使用示例
string recvStr = ""; byte[] recvBytes = new byte[1024]; int bytes; bytes = temp.Receive(recvBytes, recvBytes.Length, 0);//從客戶端接受信息 recvStr += Encoding.ASCII.GetString(recvBytes, 0, bytes);
直接從微軟那復(fù)制來(lái)的。
Receive(Byte[], Int32, Int32, SocketFlags, SocketError) | 使用指定的 Socket,從綁定的 SocketFlags 接收數(shù)據(jù),將數(shù)據(jù)存入接收緩沖區(qū)。 |
Receive(Byte[], Int32, Int32, SocketFlags) | 使用指定的 Socket,從綁定的 SocketFlags 接收指定的字節(jié)數(shù),存入接收緩沖區(qū)的指定偏移量位置。 |
Receive(IList<ArraySegment<Byte>>, SocketFlags, SocketError) | 使用指定的 Socket,從綁定的 SocketFlags 接收數(shù)據(jù),將數(shù)據(jù)存入接收緩沖區(qū)列表中。 |
Receive(Byte[], Int32, SocketFlags) | 使用指定的 Socket,從綁定的 SocketFlags 接收指定字節(jié)數(shù)的數(shù)據(jù),并將數(shù)據(jù)存入接收緩沖區(qū)。 |
Receive(Byte[], SocketFlags) | 使用指定的 Socket,從綁定的 SocketFlags 接收數(shù)據(jù),將數(shù)據(jù)存入接收緩沖區(qū)。 |
Receive(IList<ArraySegment<Byte>>, SocketFlags) | 使用指定的 Socket,從綁定的 SocketFlags 接收數(shù)據(jù),將數(shù)據(jù)存入接收緩沖區(qū)列表中。 |
Receive(IList<ArraySegment<Byte>>) | 從綁定的 Socket 接收數(shù)據(jù),將數(shù)據(jù)存入接收緩沖區(qū)列表中。 |
Receive(Byte[]) | 從綁定的 Socket 套接字接收數(shù)據(jù),將數(shù)據(jù)存入接收緩沖區(qū)。 |
參數(shù)
Byte[] buffer
Byte類型的數(shù)組,它是存儲(chǔ)接收到的數(shù)據(jù)的位置。
Int32 offset
buffer
參數(shù)中的位置,用于存儲(chǔ)所接收的數(shù)據(jù)。
Int32 size
要接收的字節(jié)數(shù)。
SocketFlags socketFlags
SocketFlags值的按位組合。
SocketError errorCode
一個(gè)SocketError對(duì)象,它存儲(chǔ)套接字錯(cuò)誤。
socketFlags 默認(rèn)值為0 或 None ,筆者沒(méi)有搞懂socketFlags 的應(yīng)用場(chǎng)景。
返回
返回已成功讀取的字節(jié)數(shù)。
Send()
send()跟Receive()用法相似,
示例代碼如下
string str = "hello"; byte[] a = Encoding.UTF8.GetBytes(str); send = socket.Send(a, 0);
發(fā)送/接收 都是使用 byte[] 字節(jié)流,所以接收時(shí)要進(jìn)行轉(zhuǎn)換。
六,釋放資源
有 Accept 釋放和 Socket 的釋放。
Accept 是連接對(duì)象,一個(gè) Socket 可能有數(shù)十個(gè) Accept 連接。
使用 Shutdown( ) 方法可以 禁止 Asscpt 對(duì)象的操作(禁用某個(gè) Socket 對(duì)象 的發(fā)送和接收)。
public void Shutdown (System.Net.Sockets.SocketShutdown how);
SocketShutdown 是一個(gè) enum 類型。
實(shí)例
temp.Shutdown(SocketShutdown.Receive); //禁止接收
值 | 使用 | 描述 |
---|---|---|
發(fā)送 | Send | 禁止對(duì)此發(fā)送Socket。 |
接收 | Receive | 禁用對(duì)此接收Socket。 |
消息和傳送 | Both | 禁用發(fā)送和接收對(duì)此Socket。 |
close()
會(huì)直接釋放資源,Accept 和 Socket 對(duì)象都可以使用。使用后對(duì)象將徹底釋放。
七,IPAddress 和IPEndPoint
//引入 using System.Net;
IPAddress 用來(lái)處理IP地址、轉(zhuǎn)換IP地址
IPAddress.Parse() 方法可以把以小數(shù)點(diǎn)隔分的十進(jìn)制 IP 表示轉(zhuǎn)化成 IPAddress 類。
IPAddress ip = IPAddress.Parse("127.0.0.1");//把ip地址字符串轉(zhuǎn)換為IPAddress類型的實(shí)例
IPAddress提供4個(gè)只讀字段
- Any 用于代表本地系統(tǒng)可用的任何IP地址
- Broadcase用于代表本地網(wǎng)絡(luò)的IP廣播地址
- Loopback用于代表系統(tǒng)的回送地址
- None用于代表系統(tǒng)上沒(méi)有網(wǎng)絡(luò)接口
關(guān)于其類型的使用和全部方法、構(gòu)造函數(shù)等,請(qǐng)查看文檔Microsoft文檔。
地址https://docs.microsoft.com/zh-cn/dotnet/api/system.net.ipaddress?view=netframework-4.7.2
IPEndPoint 表示IPAddress對(duì)象與端口的綁定
IPAddress ip = IPAddress.Any; //把ip地址字符串轉(zhuǎn)換為IPAddress類型的實(shí)例 IPEndPoint ipe = new IPEndPoint(ip, 8000);//用指定的端口和ip初始化IPEndPoint類的新實(shí)例
上面的代碼,創(chuàng)建一個(gè)監(jiān)控點(diǎn),端口是 8000,對(duì)象是 本地所有IP。
另外,此類能夠獲取查看端口的值范圍,除此外,此類沒(méi)有太大意義。
Microsoft 文檔地址https://docs.microsoft.com/zh-cn/dotnet/api/system.net.ipendpoint?view=netframework-4.7.2
到此這篇關(guān)于C#中的Socket編程詳解的文章就介紹到這了。希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
WPF實(shí)現(xiàn)多運(yùn)算符表達(dá)式計(jì)算器
這篇文章主要為大家詳細(xì)介紹了WPF實(shí)現(xiàn)多運(yùn)算符表達(dá)式計(jì)算器,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-11-11WPF+WriteableBitmap實(shí)現(xiàn)高性能曲線圖的繪制
這篇文章主要為大家詳細(xì)介紹了如何利用WPF+WriteableBitmap實(shí)現(xiàn)高性能曲線圖的繪制,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以嘗試一下2022-08-08C# 實(shí)現(xiàn)TXT文檔轉(zhuǎn)Table的示例代碼
這篇文章主要介紹了C# 實(shí)現(xiàn)TXT文檔轉(zhuǎn)Table的示例代碼,幫助大家更好的理解和學(xué)習(xí)c#,感興趣的朋友可以了解下2020-12-12winform 實(shí)現(xiàn)選擇文件和選擇文件夾對(duì)話框的簡(jiǎn)單實(shí)例
下面小編就為大家?guī)?lái)一篇winform 實(shí)現(xiàn)選擇文件和選擇文件夾對(duì)話框的簡(jiǎn)單實(shí)例。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-01-01C#在運(yùn)行時(shí)動(dòng)態(tài)創(chuàng)建類型的實(shí)現(xiàn)方法
這篇文章主要介紹了C#在運(yùn)行時(shí)動(dòng)態(tài)創(chuàng)建類型的實(shí)現(xiàn)方法,主要通過(guò)動(dòng)態(tài)生成C#代碼再編譯成程序集來(lái)實(shí)現(xiàn)動(dòng)態(tài)創(chuàng)建類型的,需要的朋友可以參考下2014-09-09c#中object、var和dynamic的區(qū)別小結(jié)
這篇文章主要給大家介紹了關(guān)于c#中object、var和dynamic的區(qū)別,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-09-09