UDPを使う
UDPとは
UDPはデータが宛先に届いたかどうかをUDPは関知しないため、TCPと異なりデータの到着を保障しません。 そのため、UDPを使った通信を行うプログラムを書く場合には、パケットがネットワークの途中で消えてしまうことも想定しなくてはなりません。 このような制約がUDPにはあるため、確実にデータを届けたいアプリケーションではTCPを使うのが一般的です。
このように書くとUDPは使いにくいだけに思えますが、利点もあります。
- 複数の相手に同時にデータを送信できる(ブロードキャスト、マルチキャスト)
- TCPよりもリアルタイム性が高い
まず、第一の利点として複数の相手に同時にデータ送信ができる事が挙げられます。 IPの通信形態には、ユニキャスト、ブロードキャスト、マルチキャストの3種類があります。 (ただし、IPv6にはブロードキャストはありません。) TCPでは、1対1の通信しかできないのでユニキャストしかサポートしていません。 UDPでは、一つデータパケットを送ればネットワークで必要に応じて増やして送ってくるブロードキャストやマルチキャストが利用できます。 ブロードキャストやマルチキャストを利用すると、送信側のアプリケーションの負荷を大きく軽減できます。
第二の利点としてはリアルタイム性が挙げられます。 TCPはデータの到着を保障するため、ネットワークでパケットが消えると再送します。 この再送によって、リアルタイム性が損なわれる事があります。 また、TCPはネットワークが混雑しているとデータ送信量を減らす輻輳制御を行います。 この輻輳制御によってもTCPのリアルタイム性が損なわれています。 リアルタイム性を損なう再送や輻輳制御がUDPにはないため、UDPはTCPよりもリアルタイム性が高くなります。
UDPには、上記のようなTCPにない利点があります。 UDPは、これらの利点を生かしたアプリケーションに使われるのが一般的です。 UDPを使った一般的なアプリケーションとしては、例えば、映像や音声のストリーミングや、IP電話などのVoIP(Voice over IP)などが挙げられます。 音声などを使って通話をするアプリケーションは、全ての音が正しく届く事よりもリアルタイム性が重要視されます。
UDPプログラミング
UDPの通信では、TCPのように接続を確立してから通信を行いません。 そのため、直感的にどちらがサーバだかわからない場合があります。 ここでは「サーバ、クライアント」という表現はせずに、「UDP送信プログラム、UDP受信プログラム」という表現をしたいと思います。
UDPによる通信を行うプログラムの書き方は受信と送信で異なります。 以下に、UDP受信とUDP送信のプログラム作成手順概要を示します。
- UDP受信
-
- ソケットを作る
- bindするIPアドレスとポートを設定する
- ソケットに名前をつける(bindする)
- データを受け取る
- UDP送信
-
UDP送信プログラムは、特定のIPアドレス+UDPポート番号で待っているサーバに対してパケットを送信します。
- ソケットを作る
- 宛先を指定して送信する
単純なUDP受信プログラム
winsockを使った簡単なUDP受信プログラムのサンプルを以下に示します。 コードを簡単にするため、エラー処理は省いてあります。 実際にコードを書く場合にはエラー処理も行ったコードにして下さい。
#include <stdio.h>
#include <winsock2.h>
int
main()
{
WSAData wsaData;
SOCKET sock;
struct sockaddr_in addr;
char buf[2048];
WSAStartup(MAKEWORD(2,0), &wsaData);
sock = socket(AF_INET, SOCK_DGRAM, 0);
addr.sin_family = AF_INET;
addr.sin_port = htons(12345);
addr.sin_addr.S_un.S_addr = INADDR_ANY;
bind(sock, (struct sockaddr *)&addr, sizeof(addr));
memset(buf, 0, sizeof(buf));
recv(sock, buf, sizeof(buf), 0);
printf("%s\n", buf);
closesocket(sock);
WSACleanup();
return 0;
}
上記UDP受信プログラムは、UDP送信プログラムから送られてきたデータを表示して終了します。
単純なUDP送信プログラム
winsockを使った簡単なUDP送信プログラムのサンプルを以下に示します。 コードを簡単にするため、エラー処理は省いてあります。 実際にコードを書く場合にはエラー処理も行ったコードにして下さい。
#include <winsock2.h>
int
main()
{
WSAData wsaData;
SOCKET sock;
struct sockaddr_in addr;
WSAStartup(MAKEWORD(2,0), &wsaData);
sock = socket(AF_INET, SOCK_DGRAM, 0);
addr.sin_family = AF_INET;
addr.sin_port = htons(12345);
addr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
sendto(sock, "HELLO", 5, 0, (struct sockaddr *)&addr, sizeof(addr));
closesocket(sock);
WSACleanup();
return 0;
}
上記UDP送信プログラムは、UDP受信プログラムに対してデータを送信して終了します。 上記UDP送信プログラムの動作を確認するためには、あらかじめUDP受信プログラムを起動しておく必要があります。