文章目錄
- 0、寫在前面的話
- 1、Socket 介紹
- 1.1 Socket是什么
- 1.2 Socket在網絡中的位置
- 2、C# 中的Socket參數
- 2.1 超時控制參數
- 2.2 緩沖區參數
- 2.3 UDP專用參數
- 3、C# 中的Socket API
- 3.1 Socket(構造函數)
- 3.1.1 SocketType
- 3.1.2 ProtocolType
- 3.1.3 AddressFamily
- 3.2 Bind()
- 3.3 Connect()
- 3.4 Listen()
(TCP)
- 3.5 Accept()
(TCP)
- 3.6 Receive() 與 Send()
- 3.7 ReceiveFrom()與SendTo()
- 3.8 Shutdown()和Close()
- 4、IPAddress 和 IPEndPoint
- 4.1 IPAddress
- 4.2 IPEndPoint
0、寫在前面的話
我創建的Unity、C#交流群,有興趣可加入大家一起學習:952914223
1、Socket 介紹
1.1 Socket是什么
Socket的英文原意是“插座”,的意思,通常在計算機編程中稱作套接字,是對對于TCP/IP的封裝,我們可以將Socket聯想成是由兩個Socket對象搭建的成的一根通信管道,管道的兩端是這兩個Socket對象,而這根管道的連接的是兩臺主機的應用進程(通過IP地址和端口號確定進程)
1.2 Socket在網絡中的位置
2、C# 中的Socket參數
2.1 超時控制參數
- ReceiveTimeout:接收超時
socket.ReceiveTimeout = 5000; // 5秒(單位:毫秒)
// 超時拋出SocketException,ErrorCode為10060 (TimedOut)
- SendTimeout:發送超時
socket.SendTimeout = 3000; // 3秒
// 影響Send/SendTo操作
- BeginConnect:連接超時
// 通過Connect方法的異步版本實現
socket.BeginConnect(remoteEP, null, null);
if(!socket.Connected) {// 自定義超時邏輯
}
2.2 緩沖區參數
- ReceiveBufferSize:接收緩沖區大小
socket.ReceiveBufferSize = 65536; // 64KB
// 影響內核網絡棧的接收緩沖區
- SendBufferSize:發送緩沖區大小
socket.SendBufferSize = 32768; // 32KB
// 影響內核網絡棧的發送緩沖區
2.3 UDP專用參數
- EnableBroadcast:啟用廣播
udpSocket.EnableBroadcast = true;
// 允許發送到廣播地址(如255.255.255.255)
- 多播設置
// 加入多播組
udpSocket.SetSocketOption(SocketOptionLevel.IP,SocketOptionName.AddMembership,new MulticastOption(IPAddress.Parse("224.0.0.1")));// 設置多播TTL
udpSocket.SetSocketOption(SocketOptionLevel.IP,SocketOptionName.MulticastTimeToLive,2); // 最多跨越2個路由器
3、C# 中的Socket API
3.1 Socket(構造函數)
public Socket(SocketInformation socketInformation);
public Socket(SocketType socketType, ProtocolType protocolType);
public Socket(AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType);
常見的 Socket 對象創建實例:
// 監控 ip4 地址,套接字類型為 TCP ,協議類型為 TCP
Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
3.1.1 SocketType
指定 Socket 類的實例表示的套接字類型。
SocketType | 對應的ProtocolType | 描述 |
---|---|---|
Unknown | Unknown | 指定未知的 Socket 類型 |
Stream(使用字節流) | Tcp | 支持可靠、雙向、基于連接的字節流 |
Dgram(使用數據報) | Udp | 面向無連接 |
Raw | Icmp、lgmp | 支持對基礎傳輸協議的訪問 |
Rdm | 支持無連接、面向消息、以可靠方式發送的消息, | |
Seqpacket | 在網絡上提供排序字節流的面向連接且可靠的雙向傳輸 |
3.1.2 ProtocolType
表示協議類型,是一個 enum 類型。
其中枚舉重復值,常見用途:
- 為舊值提供別名
- 向后兼容
- 提供更清晰的命名選擇
枚舉值 | 值 | 協議說明 |
---|---|---|
Unknown | -1 | 未知協議類型 |
Unspecified | 0 | 未指定的協議 |
IP | 0 | Internet 協議 (IP) - 原始 IP 數據包 |
IPv6HopByHopOptions | 0 | IPv6 逐跳選項頭 |
Icmp | 1 | Internet 控制消息協議 (ICMP) |
Igmp | 2 | Internet 組管理協議 (IGMP) |
Ggp | 3 | 網關到網關協議 (GGP) |
IPv4 | 4 | IPv4 協議 |
Tcp | 6 | 傳輸控制協議 (TCP) |
Pup | 12 | PARC 通用數據包協議 (PUP) |
Udp | 17 | 用戶數據報協議 (UDP) |
Idp | 22 | Internet 數據報協議 (IDP) |
IPv6 | 41 | IPv6 協議 |
IPv6RoutingHeader | 43 | IPv6 路由頭 |
IPv6FragmentHeader | 44 | IPv6 分片頭 |
IPSecEncapsulatingSecurityPayload | 50 | IPv6 封裝安全負載 (ESP) 頭 |
IPSecAuthenticationHeader | 51 | IPv6 認證頭 (AH) |
IcmpV6 | 58 | ICMP for IPv6 |
IPv6NoNextHeader | 59 | IPv6 無下一個頭 |
IPv6DestinationOptions | 60 | IPv6 目的選項頭 |
ND | 77 | Net Disk 協議 (非正式) |
Raw | 255 | 原始 IP 數據包 |
Ipx | 1000 | Internet 數據包交換協議 (IPX) |
Spx | 1256 | 順序數據包交換協議 (SPX) |
SpxII | 1257 | SPX 版本 2 |
3.1.3 AddressFamily
表示使用的網絡尋址方案
枚舉值 | 值 | 協議說明 | 使用場景 |
---|---|---|---|
Unknown | -1 | 未知地址族 | 保留值 |
Unspecified | 0 | 未指定的地址族 | 通用情況 |
Unix | 1 | Unix本地通信 | Unix域Socket |
InterNetwork | 2 | IPv4地址族 | 最常用的IPv4網絡 |
ImpLink | 3 | ARPANET IMP地址 | 歷史遺留 |
Pup | 4 | PUP協議地址 | Xerox PUP網絡 |
Chaos | 5 | MIT CHAOS協議 | 歷史遺留 |
NS | 6 | Xerox NS協議 | Xerox網絡系統 |
Ipx | 6 | IPX/SPX地址 | Novell網絡 |
Iso | 7 | ISO協議 | OSI協議族 |
Osi 7 | OSI協議 | 同Iso | |
Ecma | 8 | ECMA協議 | 歐洲計算機制造商協會 |
DataKit | 9 | Datakit協議 | AT&T Datakit |
Ccitt 10 | CCITT協議 | TU-T協議 | |
Sna | 11 | IBM SNA地址 | IBM系統網絡架構 |
DecNet | 12 DECnet地址 | Digital Equipment Corporation網絡 | |
DataLink | 13 | 直接數據鏈路接口 | 數據鏈路層訪問 |
Lat | 14 | LAT地址 | Local Area Transport |
HyperChannel | 15 | NSC Hyperchannel | Network Systems Corporation |
AppleTalk | 16 | AppleTalk地址 | Apple網絡協議 |
NetBios | 17 | NetBios地址 | Windows網絡基本輸入輸出系統 |
VoiceView | 18 | VoiceView地址 | VoiceView音頻協議 |
FireFox | 19 | FireFox協議 | 非標準協議 |
Banyan | 21 | Banyan VINES | Banyan虛擬網絡系統 |
Atm | 22 | 本機ATM服務 | 異步傳輸模式 |
InterNetworkV6 | 23 | IPv6地址族 | IPv6網絡 |
Cluster | 24 | Microsoft Wolfpack | Microsoft集群服務 |
Ieee12844 | 25 | IEEE 1284.4工作組 | 打印機共享協議 |
Irda | 26 | IrDA地址 | 紅外數據協會 |
NetworkDesigners | 28 | Network Designers OSI網關 | 網絡設計者協議 |
Max | 29 | 最大地址族 | 保留值 |
3.2 Bind()
綁定本地IP和端口,你將在在本地創建 IPEndPoint 對象,擁有此 ip:post 的訪問權限。目的是綁定本地機器的某個端口,所有經過此端口的數據就歸你管了。
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");serverSocket.Bind(new IPEndPoint(iP, 2300))
3.3 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);
3.4 Listen() (TCP)
監控所有發送到此主機的、特定端口的連接請求。服務端使用,客戶端不需要。
public void Listen (int backlog);
使用 Bind() 后,使用 Listen() 方法進行監控,backlog 參數指定可排隊等待接受的傳入連接的數量,即掛起的連接隊列的最大長度。
3.5 Accept() (TCP)
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
注意的是,每次建立連接是一個 Accept() 對象,如果你要進行 服務器-客戶端互相通訊,應使用同一個 Accept() 對象。每個 Accept 對象都是 從客戶端請求建立開始的,期間只要使用同一個 Accept 對象,都可以進行數據傳輸。
3.6 Receive() 與 Send()
- Receive() :接收信息
string recvStr = "";
byte[] recvBytes = new byte[1024];
int bytes;
bytes = socket.Receive(recvBytes, recvBytes.Length, 0);//從客戶端接受信息
recvStr += Encoding.ASCII.GetString(recvBytes, 0, bytes);
- Send() :發送信息
string str = "hello";
byte[] a = Encoding.UTF8.GetBytes(str);
send = socket.Send(a, 0);
3.7 ReceiveFrom()與SendTo()
- ReceiveFrom()
特性 | Receive | ReceiveFrom |
---|---|---|
連接要求 | 需要已建立連接 (面向連接) | 無需預先連接 (無連接) |
適用協議 | TCP UDP | |
來源獲取 | 無法獲取發送方信息 | 可獲取發送方的端點信息 |
方法簽名 | int Receive(byte[] buffer) | int ReceiveFrom(byte[] buffer, ref EndPoint remoteEP) |
典型用途 | 可靠數據流傳輸 | 數據報接收,特別是需要回復的場景 |
- SendTo()
特性 | Send | SendTo |
---|---|---|
連接要求 | 需要已建立連接 (面向連接) | 無需預先連接 (無連接) |
適用協議 | TCP | UDP |
目標指定 | 在Connect時指定目標 | 每次發送時指定目標 |
性能 | 略高 (連接已建立) | 略低 (每次需解析地址) |
可靠性 | 高 (TCP保證送達和順序) | 低 (UDP不保證送達和順序) |
方法簽名 | Send(byte[] buffer) | SendTo(byte[] buffer, EndPoint remoteEP) |
3.8 Shutdown()和Close()
釋放資源,有 Accept 釋放和 Socket 的釋放。
- Shutdown()
- 向對方發送FIN包,啟動TCP的正常關閉握手流程
- 非破壞性操作,Socket對象仍然有效
- 允許完成正在進行的數據傳輸
- 遵循TCP協議的四次揮手過程
- 對方應用會收到EOF(Receive返回0)
public void Shutdown (System.Net.Sockets.SocketShutdown how);
SocketShutdown:
值 | 描述 |
---|---|
Send | 禁止對此發送Socket |
Receive | 禁用對此接收Socket |
Both | 禁用發送和接收對此Socket |
- Close()
- 破壞性操作,Socket對象不再可用
- 可能丟失發送/接收緩沖區中的數據
- 對方可能收到ConnectionReset錯誤
- 立即釋放系統資源
- 最佳實踐
void SafeClose(Socket socket)
{try{// 1. 先優雅關閉通信通道if(socket.Connected){socket.Shutdown(SocketShutdown.Both);}// 2. 設置linger選項確保數據發送socket.LingerState = new LingerOption(true, 5); // 等待5秒// 3. 最終釋放資源socket.Close();}catch(Exception ex){// 記錄日志Debug.WriteLine($"關閉Socket異常: {ex.Message}");// 確保資源釋放socket?.Close(); }
}
4、IPAddress 和 IPEndPoint
4.1 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用于代表系統上沒有網絡接口
4.2 IPEndPoint
表示IPAddress對象與端口的綁定
IPAddress ip = IPAddress.Any; //把ip地址字符串轉換為IPAddress類型的實例
IPEndPoint ipe = new IPEndPoint(ip, 8000);//用指定的端口和ip初始化IPEndPoint類的新實例