首頁 > 軟體

C#中的Socket程式設計詳解

2022-01-14 19:01:12

文章按照 Socket 的 建立、連線、傳輸資料、釋放資源的過程來寫。給出方法、引數的詳細資訊。

一,網路基礎

說到 Socket,需要學習一下TCP/IP的知識,瞭解一下OSI 網路模。

推薦別人的文章,可以很快地瞭解這些。

https://www.jb51.net/article/234633.htm

https://www.jb51.net/article/234653.htm

二,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 型別。

其所有欄位如下

SocketType

  值 

對應的ProtocolType

描述

Unknown

-1

  Unknown              

指定未知的 Socket 型別。

Stream(使用位元組流)

1

Tcp

支援可靠、雙向、基於連線的位元組流

Dgram(使用資料包)

2

Udp

面向無連線

Raw

3

Icmp、lgmp

支援對基礎傳輸協定的存取

Rdm

4

 

支援無連線、訊息導向、以可靠方式傳送的訊息,

並保留資料中的訊息邊界

Seqpacket

5

 

在網路上提供排序位元組流的面向連線且可靠的雙向傳輸

AddressFamily

表示使用的網路定址方案,是一個 enum 型別。

地址型別

描述

AppleTalk16

AppleTalk 地址。

Atm22

本機 ATM 服務地址。

Banyan21

Banyan 地址。

Ccitt10

CCITT 協定(如 X.25)的地址。

Chaos5

MIT CHAOS 協定的地址。

Cluster24

Microsoft 群集產品的地址。

DataKit9

Datakit 協定的地址。

DataLink13

直接資料連結介面地址。

DecNet12

DECnet 地址。

Ecma8

歐洲計算機制造商協會 (ECMA) 地址。

FireFox19

FireFox 地址。

HyperChannel15

NSC Hyperchannel 地址。

Ieee1284425

IEEE 1284.4 工作組地址。

ImpLink3

ARPANET IMP 地址。

InterNetwork2

IP 版本 4 的地址。

InterNetworkV623

IP 版本 6 的地址。

Ipx6

IPX 或 SPX 地址。

Irda26

IrDA 地址。

Iso7

ISO 協定的地址。

Lat14

LAT 地址。

Max29

MAX 地址。

NetBios17

NetBios 地址。

NetworkDesigners28

支援網路設計器 OSI 閘道器的協定的地址。

NS6

Xerox NS 協定的地址。

Osi7

OSI 協定的地址。

Pup4

PUP 協定的地址。

Sna11

IBM SNA 地址。

Unix1

Unix 本地到主機地址。

Unknown-1

未知的地址族。

Unspecified0

未指定的地址族。

VoiceView18

VoiceView 地址。

Socket 官方檔案地址

https://docs.microsoft.com/zh-cn/dotnet/api/system.net.sockets.socket?redirectedfrom=MSDN&view=netframework-4.7.2

三,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

到此這篇關於C#中的Socket程式設計詳解的文章就介紹到這了。希望對大家的學習有所幫助,也希望大家多多支援it145.com。


IT145.com E-mail:sddin#qq.com