hozugawa.net · A neutral informational page

Winsock socket関数でTCP/UDPソケットを作成する手順

ネットワークプログラミングを始めるにあたって、Windows環境では Winsock (Windows Sockets) API が標準的に利用されます。通信の基盤となるソケットを生成するのが socket 関数であり、トランスポート層プロトコルとして TCP と UDP を選ぶかでソケットの性質が大きく変わります。本記事では、ソケット作成に必要なパラメータ、典型的な呼び出しコード、そしてエラー時の確認ポイントまでを順に整理します。

ソケット作成は、その後の bind、accept、connect、send、recv といった一連の操作の入口になります。プロトコルの選定からディスクリプタの管理まで、最初の一歩を正しく押さえておくことが、安定した通信実装への近道となります。

socket関数の基本仕様

Winsock2 で提供される socket 関数のプロトタイプは次の通りです。引数はアドレスファミリ、ソケットタイプ、プロトコルの三つから構成されています。

SOCKET WSAAPI socket(
  int af,
  int type,
  int protocol
);

戻り値は SOCKET 型で、失敗時には INVALID_SOCKET が返されます。値の判定には定数比較を用い、符号付き整数との比較は避けてください。第一引数には AF_INET (IPv4) または AF_INET6 (IPv6) を、第二引数には用途に応じたソケットタイプを、第三引数には通常 0 を渡すことで自動選択させます。

呼び出しに先立って、WSAStartup で Winsock を初期化しておく必要があります。対応するバージョンは MAKEWORD(2, 2) が推奨され、winsock2.h のインクルードも必須です。

TCPソケットを作成する場合

TCP でストリーム通信を行う場合は、信頼性の高いバイトストリームが得られます。コード例を示します。

SOCKET tcpSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (tcpSock == INVALID_SOCKET) {
    // エラー処理
}

SOCK_STREAM を指定すると内部的に IPPROTO_TCP が選ばれますが、明示的に IPPROTO_TCP を渡しても同じ結果になります。作成したソケットはサーバー側では bind → listen → accept、クライアント側では connect の流れで利用します。

ソケット作成後すぐに setsockopt で SO_REUSEADDR を有効化しておくと、サーバープログラムを再起動した際の "Address already in use" エラーを回避しやすくなります。

UDPソケットを作成する場合

UDP でデータグラム通信を行う場合は、コネクションレスで軽量な送受信が可能になります。コードは次の通りです。

SOCKET udpSock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (udpSock == INVALID_SOCKET) {
    // エラー処理
}

SOCK_DGRAM を指定することで、UDP のベストエフォート型通信が得られます。到達保証や順序制御はアプリケーション側で実装する必要がありますが、そのぶんオーバーヘッドが少なく、リアルタイム性が求められる用途に向いています。

UDP ソケットでは connect を省略して sendto/recvfrom を都度使うのが一般的ですが、同一ホストとの固定的な通信であれば connect した後 send/recv を使うパターンも可能です。

エラーハンドリングと WSAGetLastError

socket 関数が失敗した原因を調べるには WSAGetLastError を使います。よく返されるエラーコードには次のようなものがあります。

エラー時は WSACleanup を呼び出してリソースを解放し、必要に応じて再試行や上位層への通知を行います。エラーログにはエラーコードと発生コンテキストを併記しておくと、デバッグが容易になります。

パラメータ選択の指針

アドレスファミリには、現状では AF_INET6 が IPv4 と IPv6 の両方を扱える WSA_PROTOCOL_INFO 指定で利用できるケースもあります。プロトコル自動選択に任せるほうが、互換性確保の観点では有利です。

ソケットタイプに SOCK_RAW を指定すれば ping 相当のパケットを自前で組み立てられますが、Windows では管理者権限が必要であり、ICS 制御やネットワーク解析など特殊な用途に限られます。

プロトコル定数には IPPROTO_TCP、IPPROTO_UDP 以外にも IPPROTO_ICMP などがあります。日常的に TCP/UDP を扱う分には 0 渡しで十分なケースがほとんどです。

ソケット作成後の運用ポイント

作成したソケットは、利用が終わったら closesocket で必ずクローズします。プロセス終了時にリソースが残ると TIME_WAIT 状態が続いたり、他のプロセスがポートを掴めなくなったりする恐れがあります。

高負荷なサーバー用途では、AcceptEx を使った非同期受け入れや、IOCP (I/O Completion Port) との組み合わせが効果的です。シングルスレッド設計でも、WSAEventSelect を併用すればイベント駆動型の実装に移行できます。

ソケットオプションの調整も忘れてはなりません。TCP_NODELAY を有効にすれば Nagle アルゴリズムを無効化できますし、SO_RCVBUF と SO_SNDBUF でバッファサイズをチューニングできます。参考資料として ネットワークプログラミング参考 のような外部ドキュメントを併読しておくと、理解の補強になります。

TCPとUDPソケットの特徴比較

項目 TCP (SOCK_STREAM) UDP (SOCK_DGRAM)
接続方式 コネクション型 (connect 必須) コネクションレス
信頼性 順序保証・再送制御あり 到達・順序の保証なし
送受信API send / recv sendto / recvfrom
主な用途 Web、ファイル転送、メール DNS、VoIP、ゲーム、放送
オーバーヘッド 比較的大きい 比較的小さい
作成例 socket(AF_INET, SOCK_STREAM, IPPROTO_TCP) socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)

ソケット作成時の推奨事項

実際の開発現場では、ソケット作成だけで完結することは少なく、bind、listen、connect、send、recv、closesocket がセットになります。まずは TCP で echo サーバーを実装し、その後 UDP に拡張していくと、両者の挙動の違いを体感しやすいです。プロトコル選定は要件次第ですが、まずは socket 関数の戻り値とエラーハンドリングを確実に押さえることが、ネットワークプログラミングの土台作りにつながります。