C# でクライアントサーバー通信を設定する

Muhammad Husnain 2023年10月12日
  1. 伝送制御プロトコル(TCP)
  2. C# でクライアント/サーバー通信を設定する
C# でクライアントサーバー通信を設定する

この簡単なプログラミングチュートリアルでは、クライアントサーバー環境でのデータ送信について説明します。また、TCP ソケットプログラミングを介してクライアントサーバー通信モデルに C# ベースの実装を提供します。

伝送制御プロトコル(TCP)

オープンシステム相互接続(OSI)は、コンピューターが相互に通信する方法を説明する、広く採用されている通信参照モデルです。これにより、エラーのないデータが一方の端からもう一方の端に確実に配信されます。

階層化された OSI モデルは、データを送受信するときに従うべきいくつかのルールとプロトコルを定義します。すべてのレイヤーは個別に機能し、一方の端からもう一方の端にデータを送信するタスクを実行します。

この記事では、トランスポート層についてのみ説明します。この層で使用される主なプロトコルは伝送制御プロトコル(TCP)であり、次の主要な責任があります。

  1. 2つの端の間に接続を確立し、通信が終了したときにその接続を破棄します。
  2. 次のタスクで構成されるデータの転送:
    • データの信頼性を確保し、データが順番に転送され、エラーがないかどうかを確認します。
    • エラーがある場合はそれを検出し、失われたパケットを再送信します。
    • データパケットのフローとレートを制御します。
  3. 確認とフラグの設定。

C# でクライアント/サーバー通信を設定する

C# 言語を使用して.NETFramework でクライアント/サーバーアプリケーションを実装する方向に進みましょう。この実装は、Visual Studio Enterprise Edition 2019 を使用して行います。

クライアント側用とサーバー側用の 2つのアプリケーションを作成します。テストでは、これらのアプリケーションは両方とも同じコンピューター上にあります。

まず、クライアントアプリケーションを作成します。そのためには、Visual Studio を開き、新しいプロジェクトを作成します。

そして、プロジェクトの種類として Console Application を選択し、Next をクリックします。

コンソールアプリケーションを選択します

プロジェクト名を Client Application、ソリューション名を ClientServerApplication とします。これにより、クライアント側の新しいプロジェクトが作成されます。

クライアント側のプロジェクト名とソリューション名を設定する

サーバー側プログラミングの場合、同じソリューションで別のプロジェクトを作成します。

サーバー側のプロジェクト名とソリューション名を設定する

このプロジェクトは、同じソリューションで ServerApplication という名前になります。

プロジェクトを作成した後、Network Comms Dot Net パッケージファイルを追加する必要があります。そのためには、NuGet コンソールを使用してそれらをインストールする必要があります。

画像の次のように、[ツール]>[NuGet パッケージマネージャー]>[パッケージマネージャーコンソール]に移動します。

パッケージファイルを追加する

上の画像で強調表示されているように、ウィンドウにパッケージマネージャーコンソールが表示されます。このコンソールでは、次のコマンドを記述します。

PM > Install - Package NetworkCommsDotNet - Version 3.0.3

両方のプロジェクトにパッケージを正常にインストールした後、コーディングを開始できます。ServerApplication プロジェクトを開き、コードを記述します。

public static void ConnectServer() {
  IPHostEntry myhost = Dns.GetHostEntry("localhost");
  IPAddress ipAddr = myhost.AddressList[0];
  IPEndPoint myEndPoint = new IPEndPoint(ipAddr, 11000);

  try {
    Socket listenerSocket = new Socket(ipAddr.AddressFamily, SocketType.Stream, ProtocolType.Tcp);

    listenerSocket.Bind(myEndPoint);
    listenerSocket.Listen(5);

    Console.WriteLine("Waiting for Client Socket to Coonect...");
    Socket socketHandler = listenerSocket.Accept();

    // data from the client.
    string myData = null;
    byte[] dataBytes = null;

    while (true) {
      dataBytes = new byte[1023];
      int bytesRece = socketHandler.Receive(dataBytes);
      myData += Encoding.ASCII.GetString(dataBytes, 0, bytesRece);

      if (myData.IndexOf("<EOF>") > -1) {
        myData = myData.Remove(myData.Length - 5);
        break;
      }
    }

    Console.WriteLine("Data Received from Client : {0}", myData);

    byte[] msg = Encoding.ASCII.GetBytes("This is the test msg from server");
    socketHandler.Send(msg);
    socketHandler.Shutdown(SocketShutdown.Both);
    socketHandler.Close();
  } catch (Exception e) {
    Console.WriteLine(e.ToString());
  }

  Console.WriteLine("\n Press any key to continue...");
  Console.ReadKey();
}

次に、クライアント側で次のコードを記述します。

public static void ConnectClient() {
  byte[] myBytes = new byte[1024];

  try {
    IPHostEntry myhost = Dns.GetHostEntry("localhost");
    IPAddress ipAddr = myhost.AddressList[0];
    IPEndPoint clientEP = new IPEndPoint(ipAddr, 11000);

    Socket senderSocket = new Socket(ipAddr.AddressFamily, SocketType.Stream, ProtocolType.Tcp);

    try {
      // Connect to the EndPoint
      senderSocket.Connect(clientEP);

      Console.WriteLine("Client Connect to Server at {0}", senderSocket.RemoteEndPoint.ToString());

      // Convert the string into a byte-type array.
      Console.WriteLine("Sending a test message");
      byte[] msg = Encoding.ASCII.GetBytes("This is a test message from Client<EOF>");

      // Send the data using the socket.
      int dataSent = senderSocket.Send(msg);

      // Receive the reply from the server device.
      int dataRec = senderSocket.Receive(myBytes);
      Console.WriteLine("Data Received from Server = {0}",
                        Encoding.ASCII.GetString(myBytes, 0, dataRec));

      // delete the socket
      senderSocket.Shutdown(SocketShutdown.Both);
      senderSocket.Close();
      Console.ReadKey();

    } catch (ArgumentNullException ane) {
      Console.WriteLine(ane.ToString());
    } catch (SocketException se) {
      Console.WriteLine(se.ToString());
    } catch (Exception e) {
      Console.WriteLine(e.ToString());
    }

  } catch (Exception e) {
    Console.WriteLine(e.ToString());
  }
}

対応するプロジェクトのメイン関数でこれらの関数を呼び出した後、プロジェクトをビルドする必要があります。または、ソリューション全体をビルドすることもできます。次に、出力を実行するために、これらのプロジェクトのファイルエクスプローラーに移動し、両方の exe ファイルを実行します。

次の出力が受信されます。

クライアント/サーバー通信-出力

Muhammad Husnain avatar Muhammad Husnain avatar

Husnain is a professional Software Engineer and a researcher who loves to learn, build, write, and teach. Having worked various jobs in the IT industry, he especially enjoys finding ways to express complex ideas in simple ways through his content. In his free time, Husnain unwinds by thinking about tech fiction to solve problems around him.

LinkedIn