使用通訊端來透過 TCP 傳送和接收資料

在您使用通訊端與遠端裝置進行通訊之前,必須先使用通訊協定和網路位址資訊初始化通訊端。 Socket 類別的建構函式所擁有的參數,可指定通訊端用來建立連線的位址家族、通訊端類型和通訊協定類型。 將用戶端通訊端連線到伺服器通訊端時,用戶端會使用 IPEndPoint 物件來指定伺服器的網路位址。

建立 IP 端點

使用 System.Net.Sockets 時,您會將網路端點表示為 IPEndPoint 物件。 IPEndPoint 是以 IPAddress 及其對應的連接埠號碼來建構。 在透過 Socket 起始交談之前,您要先建立應用程式和遠端目的地之間的資料管道。

TCP/IP 會使用網路位址和服務連接埠編號來唯一識別服務。 網路位址可識別特定網路目的地;連接埠號碼則可識別該裝置上要連線的特定服務。 網路位址和服務連接埠的組合稱為端點,在 .NET 中是以 EndPoint 類別表示。 每個支援的位址系列已定義 EndPoint 的子系;對於 IP 位址系列,此類別是 IPEndPoint

Dns 類別會提供網域名稱服務給使用 TCP/IP 網際網路服務的應用程式。 GetHostEntryAsync 方法會查詢 DNS 伺服器,以將使用者易記的網域名稱 (例如 "host.contoso.com") 對應到數字的網際網路位址 (例如 192.168.1.1)。 GetHostEntryAsync 會傳回 Task<IPHostEntry>,在等待時其中包含位址和所要求名稱之別名的清單。 在大部分情況下,您可以使用 AddressList 陣列中傳回的第一個位址。 下列程式碼可取得包含伺服器 host.contoso.com 之 IP 位址的 IPAddress

IPHostEntry ipHostInfo = await Dns.GetHostEntryAsync("host.contoso.com");
IPAddress ipAddress = ipHostInfo.AddressList[0];

提示

針對手動測試和偵錯目的,您通常可以使用 GetHostEntryAsync 方法來取得指定 Dns.GetHostName() 值,將 localhost 名稱解析為 IP 位址。

Internet Assigned Numbers Authority (IANA) 定義了通用服務的連接埠號碼。 如需詳細資訊,請參閱 IANA:服務名稱和傳輸通訊協定連接埠號碼登錄)。 其他服務的已登錄連接埠編號範圍可以是 1,024 到 65,535。 下列程式碼會合併 host.contoso.com 的 IP 位址與連接埠號碼,以建立連線的遠端端點。

IPEndPoint ipEndPoint = new(ipAddress, 11_000);

在判斷遠端裝置的位址並選擇要用於連線的連接埠之後,應用程式可以建立與遠端裝置的連線。

建立 Socket 用戶端

建立 endPoint 物件之後,建立用戶端通訊端以連線到伺服器。 連線通訊端之後,就可以從伺服器通訊端連線傳送和接收資料。

using Socket client = new(
    ipEndPoint.AddressFamily, 
    SocketType.Stream, 
    ProtocolType.Tcp);

await client.ConnectAsync(ipEndPoint);
while (true)
{
    // Send message.
    var message = "Hi friends 👋!<|EOM|>";
    var messageBytes = Encoding.UTF8.GetBytes(message);
    _ = await client.SendAsync(messageBytes, SocketFlags.None);
    Console.WriteLine($"Socket client sent message: \"{message}\"");

    // Receive ack.
    var buffer = new byte[1_024];
    var received = await client.ReceiveAsync(buffer, SocketFlags.None);
    var response = Encoding.UTF8.GetString(buffer, 0, received);
    if (response == "<|ACK|>")
    {
        Console.WriteLine(
            $"Socket client received acknowledgment: \"{response}\"");
        break;
    }
    // Sample output:
    //     Socket client sent message: "Hi friends 👋!<|EOM|>"
    //     Socket client received acknowledgment: "<|ACK|>"
}

client.Shutdown(SocketShutdown.Both);

在上述 C# 程式碼中:

建立 Socket 伺服器

若要建立伺服器通訊端,endPoint 物件可以在任何 IP 位址上接聽連入連線,但必須指定連接埠號碼。 建立通訊端之後,伺服器就可以接受連入連線,並與用戶端通訊。

using Socket listener = new(
    ipEndPoint.AddressFamily,
    SocketType.Stream,
    ProtocolType.Tcp);

listener.Bind(ipEndPoint);
listener.Listen(100);

var handler = await listener.AcceptAsync();
while (true)
{
    // Receive message.
    var buffer = new byte[1_024];
    var received = await handler.ReceiveAsync(buffer, SocketFlags.None);
    var response = Encoding.UTF8.GetString(buffer, 0, received);
    
    var eom = "<|EOM|>";
    if (response.IndexOf(eom) > -1 /* is end of message */)
    {
        Console.WriteLine(
            $"Socket server received message: \"{response.Replace(eom, "")}\"");

        var ackMessage = "<|ACK|>";
        var echoBytes = Encoding.UTF8.GetBytes(ackMessage);
        await handler.SendAsync(echoBytes, 0);
        Console.WriteLine(
            $"Socket server sent acknowledgment: \"{ackMessage}\"");

        break;
    }
    // Sample output:
    //    Socket server received message: "Hi friends 👋!"
    //    Socket server sent acknowledgment: "<|ACK|>"
}

在上述 C# 程式碼中:

  • 具現化具有指定 endPoint 執行個體位址系列、SocketType.Stream、和 ProtocolType.Tcp 的新 Socket 物件。

  • listener 會使用 endPoint 執行個體作為引數來呼叫 Socket.Bind 方法,以將通訊端與網路位址產生關聯。

  • 系統會呼叫 Socket.Listen() 方法來接聽連入連線。

  • listener 會呼叫 Socket.AcceptAsync 方法來接受 handler 通訊端上的連入連線。

  • while 迴圈中:

    • 呼叫 Socket.ReceiveAsync 以接收用戶端的資料。
    • 收到資料時,會解碼並寫入主控台。
    • 如果 response 訊息結尾為 <|EOM|>,則會使用 Socket.SendAsync 將通知傳送至用戶端。

執行範例用戶端和伺服器

先啟動伺服器應用程式,然後啟動用戶端應用程式。

dotnet run --project socket-server
Socket server starting...
Found: 172.23.64.1 available on port 9000.
Socket server received message: "Hi friends 👋!"
Socket server sent acknowledgment: "<|ACK|>"
Press ENTER to continue...

用戶端應用程式會將訊息傳送至伺服器,而伺服器會以通知回應。

dotnet run --project socket-client
Socket client starting...
Found: 172.23.64.1 available on port 9000.
Socket client sent message: "Hi friends 👋!<|EOM|>"
Socket client received acknowledgment: "<|ACK|>"
Press ENTER to continue...

另請參閱