UDPを使う

ここでは、Mac OS Xソケットを使って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受信プログラム

Mac OS Xでの簡単なUDP受信プログラムのサンプルを以下に示します。 コードを簡単にするため、エラー処理は省いてあります。 実際にコードを書く場合にはエラー処理も行ったコードにして下さい。


#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>

int
main()
{
 int sock;
 struct sockaddr_in addr;

 char buf[2048];

 sock = socket(AF_INET, SOCK_DGRAM, 0);

 addr.sin_family = AF_INET;
 addr.sin_port = htons(12345);
 addr.sin_addr.s_addr = INADDR_ANY;
 addr.sin_len = sizeof(addr);

 bind(sock, (struct sockaddr *)&addr, sizeof(addr));

 memset(buf, 0, sizeof(buf));
 recv(sock, buf, sizeof(buf), 0);

 printf("%s\n", buf);

 close(sock);

 return 0;
}

上記UDP受信プログラムは、UDP送信プログラムから送られてきたデータを表示して終了します。

単純なUDP送信プログラム

Mac OS Xでの簡単なUDP送信プログラムのサンプルを以下に示します。 コードを簡単にするため、エラー処理は省いてあります。 実際にコードを書く場合にはエラー処理も行ったコードにして下さい。


#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>

int
main()
{
 int sock;
 struct sockaddr_in addr;

 sock = socket(AF_INET, SOCK_DGRAM, 0);

 addr.sin_family = AF_INET;
 addr.sin_port = htons(12345);
 addr.sin_addr.s_addr = inet_addr("127.0.0.1");

 sendto(sock, "HELLO", 5, 0, (struct sockaddr *)&addr, sizeof(addr));

 close(sock);

 return 0;
}

上記UDP送信プログラムは、UDP受信プログラムに対してデータを送信して終了します。 上記UDP送信プログラムの動作を確認するためには、あらかじめUDP受信プログラムを起動しておく必要があります。