【TCP/UDP通信について】
はじめに
SOCKET-MANAGER Frameworkでは、TCP通信(コネクション指向型)とUDP通信(コネクションレス型)の通信方式の違いを吸収するため、それぞれの接続を共通のディスクリプタ(クライアント接続子)で管理しています。そのため、通信データの送受信を担うUNITパラメータクラスのメソッドは、TCP/UDP通信の区別なく同じインターフェースで利用できます。
但し、エントリポイントであるメイン処理クラスでのコネクション処理と待ち受けポートの設定に関しては明確に区別する必要があるため、ソケットリソースの消費が抑えられる静的セッション管理をベースとして処理を区別しています。
以降では待ち受けポートの設定とコネクション処理に分けて、それぞれのシグネチャを見ていきます。
但し、エントリポイントであるメイン処理クラスでのコネクション処理と待ち受けポートの設定に関しては明確に区別する必要があるため、ソケットリソースの消費が抑えられる静的セッション管理をベースとして処理を区別しています。
以降では待ち受けポートの設定とコネクション処理に分けて、それぞれのシグネチャを見ていきます。
待ち受けポートの設定
シグネチャの青字の部分は省略できるパラメータを表しています。
【メソッド】listen(?string $p_host = null, ?int $p_port = null): bool 【パラメータ】 $p_host - ?string - 任意 - ホスト名。デフォルトは127.0.0.1 $p_port - ?int - 任意 - ポート番号。デフォルトは10000 【戻り値】bool(true:成功、false:失敗)
【メソッド】bind(?string $p_host = null, ?int $p_port = null): bool 【パラメータ】 $p_host - ?string - 任意 - ホスト名。デフォルトは127.0.0.1 $p_port - ?int - 任意 - ポート番号。デフォルトは10000 【戻り値】bool(true:成功、false:失敗)
コネクション処理
シグネチャの青字の部分は省略できるパラメータを表しています。
【メソッド】connect(string $p_host, int $p_port, bool $p_udp = false, int $p_retry = 0, int $p_interval = 1000): bool 【パラメータ】 $p_host - string - 必須 - ホスト名 $p_port - int - 必須 - ポート番号 $p_udp - bool - 任意 - UDP接続フラグ(true:UDP接続、false:TCP接続)。デフォルトはfalse $p_retry - int - 任意 - リトライ回数。デフォルトは0(無限) $p_interval - int - 任意 - リトライ間隔(μs)。デフォルトは1000 【戻り値】bool(true:成功、false:失敗)UDP通信の場合は、実際にコネクションを確立するわけでありませんが、共通のディスクリプタを生成するためにコールする必要があります。
UDP通信のハンドシェイク
以下のフローは、本フレームワーク内で提供される bind()/connect() メソッドを使った場合の一例ですが、UDPの通信原則に基づいて構成されているため、他の端末や独自実装のクライアントからの接続でも同様の手順で問題なく動作します。
この通信モデルでは、クライアントが最初に空のパケットを送信することで、サーバー側に接続の意志を伝えます。
サーバーはこのパケットの送信元情報をもとに仮想的な接続状態(ディスクリプタ)を生成し、応答として空パケットを返すことでハンドシェイクが完了します。
以降、クライアントはこの応答を受信した時点でサーバーの接続情報を保持し、双方向のデータ通信を開始します。
この接続情報を取得する部分は、C言語での典型的な recvfrom() 関数の使い方に例えるとイメージしやすいでしょう。
このように、サーバーは空パケットを受信するだけで、送信元のIPアドレスとポート番号を把握できるため、仮想的な接続識別子(ディスクリプタ)を生成し、通信状態を管理する基盤を構築できます。この処理を抽象化し、プロトコルに依存しない形式で実装できるのが当フレームワークの特徴のひとつです。
UDP通信にはTCPのような接続確立処理(accept)は存在しませんが、本フレームワークでは独自のハンドシェイク処理が完了した直後に、TCP通信と同様に accept ハンドラが自動的に呼び出されます。そのため、接続判定や認証シーケンスをプロトコルに依存せず統一的に実装できます。
この通信モデルでは、クライアントが最初に空のパケットを送信することで、サーバー側に接続の意志を伝えます。
サーバーはこのパケットの送信元情報をもとに仮想的な接続状態(ディスクリプタ)を生成し、応答として空パケットを返すことでハンドシェイクが完了します。
以降、クライアントはこの応答を受信した時点でサーバーの接続情報を保持し、双方向のデータ通信を開始します。
この接続情報を取得する部分は、C言語での典型的な recvfrom() 関数の使い方に例えるとイメージしやすいでしょう。
struct sockaddr_in client_addr; socklen_t addrlen = sizeof(client_addr); char buffer[1]; // 空パケットの受信と同時に送信元アドレスを取得 recvfrom(server_socket, buffer, sizeof(buffer), 0, (struct sockaddr *)&client_addr, &addrlen); // ここで client_addr にIPアドレスやポートが格納されている
このように、サーバーは空パケットを受信するだけで、送信元のIPアドレスとポート番号を把握できるため、仮想的な接続識別子(ディスクリプタ)を生成し、通信状態を管理する基盤を構築できます。この処理を抽象化し、プロトコルに依存しない形式で実装できるのが当フレームワークの特徴のひとつです。
UDP通信にはTCPのような接続確立処理(accept)は存在しませんが、本フレームワークでは独自のハンドシェイク処理が完了した直後に、TCP通信と同様に accept ハンドラが自動的に呼び出されます。そのため、接続判定や認証シーケンスをプロトコルに依存せず統一的に実装できます。
おわりに
TCP通信では、接続時にOSレベルでハンドシェイクが自動的に行われ、接続確立後には accept ハンドラを通じて認証処理などを実装することができます。
本フレームワークでは、UDP通信においても同様の開発体験を提供することで、プロトコルに依存しない統一的な接続制御とアプリケーション設計を実現しています。
本フレームワークでは、UDP通信においても同様の開発体験を提供することで、プロトコルに依存しない統一的な接続制御とアプリケーション設計を実現しています。