C# で UDP サーバーを作成する

Saad Aslam 2023年10月12日
C# で UDP サーバーを作成する

この記事では、C# で単純な UDP サーバーを作成する方法を説明します。

C# で UDP サーバーを作成する

簡単な背景として、UDP プロトコルはクライアントとの接続を構築する必要はありません。データは、クライアントがデータを受信したかどうかを認証せずに送信されます。

このタイプのプロトコルは通常、データのブロードキャストに使用されます。UDP はコネクションレス型であるため、メッセージを受信するためにリスナーがオンラインである必要はありません。

UDP を使用してデータグラムを送信するには、サービスをホストするネットワークデバイスのネットワークアドレスとサービスの UDP ポート番号を知っている必要があります。人気のあるサービスのポート番号は、Internet Assigned Numbers Authority(IANA)によって定義されています。ポート番号の範囲は 1,024〜65,535 であり、IANA リストにないサービスに割り当てることができます。

IP ベースのネットワークでは、UDP ブロードキャストメッセージを処理するために特別なネットワークアドレスが使用されます。以下の説明では、例としてインターネットの IP バージョン 4 アドレスファミリを使用しています。

ホスト ID のすべてのビットを設定することにより、ブロードキャストをネットワークの指定された部分に送信できます。アドレス 192.168.1.255 を使用して、192.168.1 で始まる IP アドレスを持つネットワーク上のすべてのホストにブロードキャストします。

これで、ソケットを構築または作成し、UDP プロトコルを設定して、すぐに通信を開始する準備が整いました。

using System;
using System.Net;
using System.Net.Sockets;
using System.Text;

これらは、サーバーのセットアップに使用されるライブラリになります。これらのライブラリは、ソケットの構築、IPV4 アドレスの処理など、ネットワークに関連するすべての基本機能をサポートします。

public class SimpleUdpSrvr {
  public static void Main() {
    int recv;
    byte[] data = new byte[1024];
    IPEndPoint ipep = new IPEndPoint(IPAddress.Any, 9050);
    Socket newsock = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
  }
}

int recv 行は、クライアントが受信した文字列メッセージのバイト数を含む整数型の recv 変数を作成します。

byte[]データ=新しいバイト [1024]; 行は、1024 セルの各セルのバイトサイズの data という名前の配列を作成するために使用されます。これは配列サイズとも呼ばれます。この配列は、ヒープ内に動的に作成されます。

IPEndPoint ipep = new IPEndPoint(IPAddress.Any, 9050); 行は、ソケットの ipep 変数を作成するように指示します。渡される情報は、使用するソケットの種類を示します。

IPEndPoint クラスは、IP アドレスとポート番号を持つネットワークエンドポイントを表します。クライアントがサービスに接続するには、この構成情報が必要です。渡される IPAddress.Any 引数は、サーバーが任意の IP アドレスで 9050 ポート番号に接続できることを示しています。ipep 変数も動的に作成されます。

Socket newsock = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);

この行は、通信するためのソケットである newsock 変数を作成します。渡される引数は、作成するソケットの種類を示します。

AddressFamily.InterNetwork は、ローカル IP アドレスが必要であることを示しています。SocketType.Dgram 引数は、データがパケットではなくデータグラムで流れる必要があることを示しています。

そして最後に、ProtocolType.Udp 引数は、使用するソケットのプロトコルタイプを示します。これで、ソケットが作成されました。

newsock.Bind(ipep);
Console.WriteLine("Waiting for a client...");

IPEndPoint sender = new IPEndPoint(IPAddress.Any, 0);
EndPoint Remote = (EndPoint)(sender);

これまで、ネットワーク内に 1つのエンドポイントと、通信するためのソケット newsock.Bind(ipep); を作成していました。line は、エンドポイントをソケットにバインドするのに役立ちます。

ipep は、エンドポイントに関する情報を持ち、newsock オブジェクトの bind() 関数に渡される変数です。

Console.WriteLine("Waiting for a client...");

この行は、サーバーがクライアントからのメッセージの送信を待機していることを画面に出力します。サーバーとの通信を試みる送信者用に別のエンドポイントを作成する必要があります。

IPEndPoint sender = new IPEndPoint(IPAddress.Any, 0);

この行は別のエンドポイントを作成し、変数は sender と呼ばれます。IPAddress.Any で渡された引数は、任意の IP アドレスを期待していることを示し、0 はそれがポート番号のワイルドカードであることを意味し、システムはそれを割り当てた適切なポートを見つけて見つける必要があります。

EndPoint Remote = (EndPoint)(sender); 行は、送信者の IP アドレスを検索し、それを remote 変数に格納するために使用されます。

recv = newsock.ReceiveFrom(data, ref Remote);

Console.WriteLine("Message received from {0}:", Remote.ToString());
Console.WriteLine(Encoding.ASCII.GetString(data, 0, recv));

プログラムの開始時に作成した recv 変数は、recv = newsock.ReceiveFrom(data, ref Remote); で使用されるようになりました。ライン。以前に作成したソケット newsockReceive() 関数を使用し、現在、その時点でソケットにあるすべてのデータを受信します。

Receive() 関数を渡す引数は、データを格納する場所と、誰のデータを格納する必要があるか、または予期されるかを示します。data 引数は渡されるバイトサイズ配列であり、データはデータ配列に書き込まれます。

ref Remote 引数は、その IP アドレスがデータを送信したことを示し、関数はそのソケットからフェッチされたバイト数を返し、それを recv 変数に格納します。

Console.WriteLine("Message received from {0}:", Remote.ToString());

この行は、ソケットを介してデータを送信したクライアントの IP アドレスを画面に書き込みます。渡された引数 Remote.ToString() は 10 進数を ASCII 文字に変換し、remote 変数はクライアントを参照する 2 番目のエンドポイントでした。

Console.WriteLine(Encoding.ASCII.GetString(data, 0, recv));

この行は、実際のデータを画面に書き込みます。ソケットを介して送信されるデータは生の形式であり、読み取るには ASCII 文字に変換する必要があります。

Encoding.ASCII.GetString(data, 0, recv) 行は、引数として渡される data 変数からデータを取得し、recv 引数(クライアントが送信したバイト数を含む)は次のように通知します。画面上の data 変数からこれらの多くのバイトを書き込みます。

string welcome = "Welcome to my test server";
data = Encoding.ASCII.GetBytes(welcome);
newsock.SendTo(data, data.Length, SocketFlags.None, Remote);

string welcome = "Welcome to my test server"; 行で、文字列変数 welcomeWelcome to my test server テキストで初期化します。

data = Encoding.ASCII.GetBytes(welcome); 行は、Encoding.ASCII.GetBytes() 関数の引数として welcome 変数を取り、それを生の形式に変換するため、もう一方の端のソケットを介して送信する準備ができています。

newsock.SendTo(data, data.Length, SocketFlags.None, Remote);

この行は、以前に作成したソケット newsock を介してデータを送信し、Send() 関数を使用します。必要な引数は次のとおりです。送信されるデータの生の形式を含む data 変数、データの長さがバイト数に等しいため、ソケットに書き込むバイト数を示す data.Length 引数、SocketFlags.None 引数は、すべてのフラグをゼロに保つように指示します。フラグはインジケーターであり、すべてのフラグにはその意味があります。

Remote 変数引数は、データを送信するクライアントについて通知します。Remote 変数は、クライアントの IP アドレスとポート番号を格納するためです。

while (true) {
  data = new byte[1024];
  recv = newsock.ReceiveFrom(data, ref Remote);

  Console.WriteLine(Encoding.ASCII.GetString(data, 0, recv));
  newsock.SendTo(data, recv, SocketFlags.None, Remote);
}

while(true) 行は、それが無限ループであり、そのすべてのステートメントが無限に実行されることを示しています。data = new byte[1024]; 行は、実行されるたびに長さ 1024 の新しいバイトサイズ配列を作成します。

recv = newsock.ReceiveFrom(data, ref Remote); 行はクライアントからデータを受け取り、それをデータ配列に保存します。

Console.WriteLine(Encoding.ASCII.GetString(data, 0, recv)); 画面にデータを書き込みます。

newsock.SendTo(data, recv, SocketFlags.None, Remote); 行は、サーバーがクライアントから受信したのと同じデータをクライアントに送り返します。

その後、サーバーは再び停止してクライアントを待機し、クライアントがサーバーに送信するものはすべて同じメッセージで応答します。このサーバーは、クラッシュするか、ユーザーが手動で停止しない限り、終了することはありません。

これで、C# で UDP サーバーを作成する方法とその基本的な機能を学習したので、要件に応じて機能を追加し、サーバーを作成できます。

完全なソースコード:

using System;
using System.Net;
using System.Net.Sockets;
using System.Text;

public class SimpleUdpSrvr {
  public static void Main() {
    int recv;
    byte[] data = new byte[1024];
    IPEndPoint ipep = new IPEndPoint(IPAddress.Any, 9050);

    Socket newsock = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);

    newsock.Bind(ipep);
    Console.WriteLine("Waiting for a client...");

    IPEndPoint sender = new IPEndPoint(IPAddress.Any, 0);
    EndPoint Remote = (EndPoint)(sender);

    recv = newsock.ReceiveFrom(data, ref Remote);

    Console.WriteLine("Message received from {0}:", Remote.ToString());
    Console.WriteLine(Encoding.ASCII.GetString(data, 0, recv));

    string welcome = "Welcome to my test server";
    data = Encoding.ASCII.GetBytes(welcome);
    newsock.SendTo(data, data.Length, SocketFlags.None, Remote);
    while (true) {
      data = new byte[1024];
      recv = newsock.ReceiveFrom(data, ref Remote);

      Console.WriteLine(Encoding.ASCII.GetString(data, 0, recv));
      newsock.SendTo(data, recv, SocketFlags.None, Remote);
    }
  }
}
著者: Saad Aslam
Saad Aslam avatar Saad Aslam avatar

I'm a Flutter application developer with 1 year of professional experience in the field. I've created applications for both, android and iOS using AWS and Firebase, as the backend. I've written articles relating to the theoretical and problem-solving aspects of C, C++, and C#. I'm currently enrolled in an undergraduate program for Information Technology.

LinkedIn

関連記事 - Csharp Server