目錄
一,網絡基礎
二,Socket 對象
三,Bind() 綁定與 Connect() 連接
四,Listen() 監聽請求連接 和 Accept() 接收連接請求
五,Receive() 與 Send()
六,釋放資源
七,IPAddress 和 IPEndPoint
2019-2-14 晚上第一次寫,后面會不斷修改、更新。
文章按照 Socket 的 創建、連接、傳輸數據、釋放資源的過程來寫。給出方法、參數的詳細信息。

一,網絡基礎
說到 Socket,需要學習一下TCP/IP的知識,了解一下OSI 網絡模。
推薦別人的文章,可以很快地了解這些。
https://www.cnblogs.com/ysyn/p/3399351.html
https://www.cnblogs.com/wangcq/p/3520400.html
二,Socket 對象
無論是服務器還是客戶端,都要創建一個 SOCKET 對象,創建方法一致。
以下是常見的 Socket 對象創建實例
Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//監控 ip4 地址,套接字類型為 TCP ,協議類型為 TCP
其有三個構造函數
public Socket(SocketInformation socketInformation);
public Socket(SocketType socketType, ProtocolType protocolType);
public Socket(AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType);
第一個構造函數,SocketInformation 對象保存的是
Socket(SocketType, ProtocolType)
實質上跟第二個構造函數是一樣的。就好像你可以直接把( 一個蘋果 , 一個梨)直接放進籃子,也可以先給 水果包裝好 再放進籃子里。
下面將解釋所有參數的意義。
SocketType
指定 Socket 類的實例表示的套接字類型。
TCP 用主機的IP地址加上主機上的端口號作為 TCP 連接的端點,這種端點就叫做套接字(socket)或插口。 套接字用(IP地址:端口號)表示。
SocketType 是 enum 類型,其字段如下
| SocketType |
值 |
對應的ProtocolType |
描述 |
| Unknown |
-1 | Unknown |
指定未知的 Socket 類型。 |
| Stream(使用字節流) |
1 |
Tcp |
支持可靠、雙向、基於連接的字節流 |
| Dgram(使用數據報) |
2 |
Udp |
面向無連接 |
| Raw |
3 |
Icmp、lgmp |
支持對基礎傳輸協議的訪問 |
| Rdm |
4 |
|
支持無連接、面向消息、以可靠方式發送的消息, 並保留數據中的消息邊界 |
| Seqpacket |
5 |
在網絡上提供排序字節流的面向連接且可靠的雙向傳輸 |
如需了解更詳細的資料,請查閱Microsoft文檔
地址: https://docs.microsoft.com/zh-cn/dotnet/api/system.net.sockets.sockettype?view=netframework-4.7.2
ProtocolType
表示協議類型,是一個 enum 類型。
其所有字段如下
| 協議類型 | 值 | 描述 |
| Ggp | 3 | 網關到網關協議。 |
| Icmp | 1 | Internet 控制消息協議。 |
| IcmpV6 | 58 | IPv6 的 Internet 控制消息協議。 |
| Idp | 22 | Internet 數據報協議。 |
| Igmp | 2 | Internet 組管理協議。 |
| IP | 0 | Internet 協議。 |
| IPSecAuthenticationHeader | 51 | IPv6 身份驗證標頭。 有關詳細信息,請參閱https://www.ietf.org 上的 RFC 2292,第 2.2.1 節。 |
| IPSecEncapsulatingSecurityPayload | 50 | IPv6 封裝安全負載標頭。 |
| IPv4 | 4 | Internet 協議版本 4。 |
| IPv6 | 41 | Internet 協議版本 6 (IPv6)。 |
| IPv6DestinationOptions | 60 | IPv6 目標選項標頭。 |
| IPv6FragmentHeader | 44 | IPv6 片段標頭。 |
| IPv6HopByHopOptions | 0 | IPv6 逐跳選項標頭。 |
| IPv6NoNextHeader | 59 | IPv6 無下一個標頭。 |
| IPv6RoutingHeader | 43 | IPv6 路由標頭。 |
| Ipx | 1000 | Internet 數據包交換協議。 |
| ND | 77 | 網絡磁盤協議(非正式)。 |
| Pup | 12 | PARC 通用數據包協議。 |
| Raw | 255 | 原始 IP 數據包協議。 |
| Spx | 1256 | 順序包交換協議。 |
| SpxII | 1257 | 順序包交換版本 2 協議。 |
| Tcp | 6 | 傳輸控制協議。 |
| Udp | 17 | 用戶數據報協議。 |
| Unknown | -1 | 未知的協議。 |
| Unspecified | 0 | 未指定的協議。 |
AddressFamily
表示使用的網絡尋址方案,是一個 enum 類型。
| 地址類型 |
值 | 描述 |
| AppleTalk | 16 | AppleTalk 地址。 |
| Atm | 22 | 本機 ATM 服務地址。 |
| Banyan | 21 | Banyan 地址。 |
| Ccitt | 10 | CCITT 協議(如 X.25)的地址。 |
| Chaos | 5 | MIT CHAOS 協議的地址。 |
| Cluster | 24 | Microsoft 群集產品的地址。 |
| DataKit | 9 | Datakit 協議的地址。 |
| DataLink | 13 | 直接數據鏈接接口地址。 |
| DecNet | 12 | DECnet 地址。 |
| Ecma | 8 | 歐洲計算機制造商協會 (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 協議的地址。 |
| Lat | 14 | LAT 地址。 |
| Max | 29 | MAX 地址。 |
| NetBios | 17 | NetBios 地址。 |
| NetworkDesigners | 28 | 支持網絡設計器 OSI 網關的協議的地址。 |
| NS | 6 | Xerox NS 協議的地址。 |
| Osi | 7 | OSI 協議的地址。 |
| Pup | 4 | PUP 協議的地址。 |
| Sna | 11 | IBM SNA 地址。 |
| Unix | 1 | Unix 本地到主機地址。 |
| Unknown | -1 | 未知的地址族。 |
| Unspecified | 0 | 未指定的地址族。 |
| VoiceView | 18 | VoiceView 地址。 |
Socket 官方文檔地址
三,Bind() 綁定與 Connect() 連接
Bind() 用於綁定 IPEndPoint 對象,在服務端使用。
Connect() 在客戶端使用,用於連接服務端。
創建 Socket 對象后,接着 綁定本地Socket / 連接服務端。
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))
你將在在本地創建 IPEndPoint 對象,擁有此 ip:post 的訪問權限。目的是綁定本地機器的某個端口,所有經過此端口的數據就歸你管了。
Connect()
與遠程主機建立連接。Connect() 有四個重載方法,不必關注,只需知道,必需提供 IP 和 Post 兩個值。
使用方法
IPAddress iP = IPAddress.Parse("127.0.0.1"); IPEndPoint iPEndPoint = new IPEndPoint(iP, 2300); Socket serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//創建與遠程主機的連接 serverSocket.Connect(iPEndPoint);
四,Listen() 監聽請求連接 和 Accept() 接收連接請求
Listen()
監控所有發送到此主機的、特點端口的連接請求。服務端使用,客戶端不需要。
public void Listen (int backlog);
使用 Bind() 后,使用 Listen() 方法進行監控,backlog 參數指定可排隊等待接受的傳入連接的數量,即掛起的連接隊列的最大長度。
示例
serverSocket.Listen(10); //開始監聽
Accept()
Accept() 以同步方式監聽套接字,在連接請求隊列中提取第一個掛起的連接請求,然后創建並返回一個新的 Socket 對象。
代碼示例
//創建終結點(EndPoint) IPAddress ip = IPAddress.Any; IPEndPoint ipe = new IPEndPoint(ip, 8000); //創建 socket 並開始監聽 Socket serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); serverSocket.Bind(ipe); serverSocket.Listen(10);//開始監聽 //接受到client連接,為此連接建立新的socket,並接受信息 Socket temp = serverSocket.Accept();//為新建連接創建新的socket
//關閉連接 temp.Close();
注意的是,每次建立連接是一個 Accept() 對象,如果你要進行 服務器-客戶端互相通訊,應使用同一個 Accept() 對象。每個 Accept 對象都是 從客戶端請求建立開始的,期間只要使用同一個 Accept 對象,都可以進行數據傳輸。
五,Receive() 與 Send()
- Receive() 接收信息
- Send() 發送信息
在服務端和客戶端都使用這兩個方法。
Receive()
使用示例
string recvStr = ""; byte[] recvBytes = new byte[1024]; int bytes; bytes = temp.Receive(recvBytes, recvBytes.Length, 0);//從客戶端接受信息 recvStr += Encoding.ASCII.GetString(recvBytes, 0, bytes);
直接從微軟那復制來的。
| Receive(Byte[], Int32, Int32, SocketFlags, SocketError) | 使用指定的 Socket,從綁定的 SocketFlags 接收數據,將數據存入接收緩沖區。 |
| Receive(Byte[], Int32, Int32, SocketFlags) | 使用指定的 Socket,從綁定的 SocketFlags 接收指定的字節數,存入接收緩沖區的指定偏移量位置。 |
| Receive(IList<ArraySegment<Byte>>, SocketFlags, SocketError) | 使用指定的 Socket,從綁定的 SocketFlags 接收數據,將數據存入接收緩沖區列表中。 |
| Receive(Byte[], Int32, SocketFlags) | 使用指定的 Socket,從綁定的 SocketFlags 接收指定字節數的數據,並將數據存入接收緩沖區。 |
| Receive(Byte[], SocketFlags) | 使用指定的 Socket,從綁定的 SocketFlags 接收數據,將數據存入接收緩沖區。 |
| Receive(IList<ArraySegment<Byte>>, SocketFlags) | 使用指定的 Socket,從綁定的 SocketFlags 接收數據,將數據存入接收緩沖區列表中。 |
| Receive(IList<ArraySegment<Byte>>) | 從綁定的 Socket 接收數據,將數據存入接收緩沖區列表中。 |
| Receive(Byte[]) | 從綁定的 Socket 套接字接收數據,將數據存入接收緩沖區。 |
參數
- Byte[] buffer
Byte 類型的數組,它是存儲接收到的數據的位置。
- Int32 offset
buffer 參數中的位置,用於存儲所接收的數據。
- Int32 size
要接收的字節數。
-
SocketFlags socketFlags
SocketFlags 值的按位組合。
- SocketError errorCode
一個 SocketError 對象,它存儲套接字錯誤。
socketFlags 默認值為 0 或 None ,筆者沒有搞懂 socketFlags 的應用場景。
返回
返回已成功讀取的字節數。
Send()
send()跟Receive()用法相似,
示例代碼如下
string str = "hello"; byte[] a = Encoding.UTF8.GetBytes(str); send = socket.Send(a, 0);
發送/接收 都是使用 byte[] 字節流,所以接收時要進行轉換。
六,釋放資源
有 Accept 釋放和 Socket 的釋放。
Accept 是連接對象,一個 Socket 可能有數十個 Accept 連接。
使用 Shutdown( ) 方法可以 禁止 Asscpt 對象的操作(禁用某個 Socket 對象 的發送和接收)。
public void Shutdown (System.Net.Sockets.SocketShutdown how);
SocketShutdown 是一個 enum 類型。
實例
temp.Shutdown(SocketShutdown.Receive); //禁止接收
| 值 | 使用 | 描述 |
|---|---|---|
| 發送 | Send | 禁止對此發送Socket。 |
| 接收 | Receive | 禁用對此接收Socket。 |
| 消息和傳送 | Both | 禁用發送和接收對此Socket。 |
close()
會直接釋放資源,Accept 和 Socket 對象都可以使用。使用后對象將徹底釋放。
七,IPAddress 和 IPEndPoint
//引入
using System.Net;
IPAddress 用來處理IP地址、轉換IP地址
IPAddress.Parse() 方法可以把以小數點隔分的十進制 IP 表示轉化成 IPAddress 類。
IPAddress ip = IPAddress.Parse("127.0.0.1");//把ip地址字符串轉換為IPAddress類型的實例
IPAddress提供4個只讀字段
- Any 用於代表本地系統可用的任何IP地址
- Broadcase用於代表本地網絡的IP廣播地址
- Loopback用於代表系統的回送地址
- None用於代表系統上沒有網絡接口
關於其類型的使用和全部方法、構造函數等,請查看文檔Microsoft文檔。
地址 https://docs.microsoft.com/zh-cn/dotnet/api/system.net.ipaddress?view=netframework-4.7.2
IPEndPoint 表示IPAddress對象與端口的綁定
IPAddress ip = IPAddress.Any; //把ip地址字符串轉換為IPAddress類型的實例 IPEndPoint ipe = new IPEndPoint(ip, 8000);//用指定的端口和ip初始化IPEndPoint類的新實例
上面的代碼,創建一個監控點,端口是 8000,對象是 本地所有IP。
另外,此類能夠獲取查看端口的值范圍,除此外,此類沒有太大意義。
Microsoft 文檔地址 https://docs.microsoft.com/zh-cn/dotnet/api/system.net.ipendpoint?view=netframework-4.7.2
SocketType
