次の方法で共有


ソケットを使用し 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 配列で返された最初のアドレスを使用できます。 次のコードは、サーバー IPAddress の IP アドレスを含む host.contoso.com を取得します。

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

ヒント

手動テストとデバッグには、通常は、GetHostEntryAsync 値の結果のホスト名と共に Dns.GetHostName() メソッドを使って、localhost 名を IP アドレスに解決できます。 次のコード スニペットを考えてみます。

var hostName = Dns.GetHostName();
IPHostEntry localhost = await Dns.GetHostEntryAsync(hostName);
// This is the IP address of the local machine
IPAddress localIpAddress = localhost.AddressList[0];

Internet Assigned Numbers Authority (IANA) により、一般的なサービス用のポート番号が定義されています。 詳細については、IANA: 「Service Name and Transport Protocol Port Number Registry (サービス名とトランスポート プロトコル ポート番号の登録)」を参照してください。 他のサービスが、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# コードでは、次のことが行われます。

  • 特定の endPoint インスタンス アドレス ファミリ、SocketType.Stream、およびProtocolType.Tcpを使用して、新しいSocket オブジェクトをインスタンス化します。

  • endPoint インスタンスを引数として使用して、Socket.ConnectAsync メソッドを呼び出します。

  • while ループの場合:

    • Socket.SendAsyncを使用してメッセージをエンコードし、サーバーに送信します。
    • 送信されたメッセージをコンソールに書き込みます。
    • Socket.ReceiveAsyncを使用して、サーバーからデータを受信するバッファーを初期化します。
    • responseが受信確認である場合、コンソールに書き込まれ、ループが終了します。
  • 最後に、 client ソケット呼び出し Socket.Shutdown 指定された SocketShutdown.Bothによって、送信操作と受信操作の両方がシャットダウンされます。

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...

こちらも参照ください