ノンブロッキングソケット

ここでは、ソケットをノンブロッキング状態にする方法を説明します。

ノンブロッキングでUDPパケットの受信を待つサンプル

通常設定では、recv関数はデータが届くまでブロッキングします。 複数のソケットを扱うプログラムや、その他入力と併用するようなプログラムではブロックさせずにrecv関数を使いたい場合があります。 Mac OS Xでは、ioctl関数にFIONBIOを渡すことにより、ブロッキング/ノンブロッキングの設定を行えます。

ノンブロッキング状態に設定したソケットでデータが無い時にrecv(もしくはread,recvfrom)を行うとrecv関数はエラーを返します。 recvがエラーを返した時のerrnoの値がEAGAINである場合には、ただ単にデータが無いという事をあらわしています。 errnoは、int errnoとして宣言されているグローバル変数です。 エラーが発生した時にエラー内容を知らせる値がセットされます。

下記サンプルでは、データが無いときには「まだ来ない」と表示し、1秒間待つという処理をしています。 下記サンプルはUDPのポート12345番にデータを受信すると、終了します。 下記サンプルへのUDPでのデータ送信には、UDP送信サンプルで示した物をご利用下さい。


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

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

 char buf[2048];
 int val;
 int n;

 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));

 /*
   ここで、ノンブロッキングに設定しています。
   val = 0でブロッキングモードに設定できます。
   ソケットの初期設定はブロッキングモードです。
 */
 val = 1;
 ioctl(sock, FIONBIO, &val);


 while (1) {
	memset(buf, 0, sizeof(buf));
	n = recv(sock, buf, sizeof(buf), 0);
	if (n < 1) {
		if (errno == EAGAIN) {
			/* まだ来ない。*/
			printf("MADA KONAI\n");
		} else {
			perror("recv");
			break;
		}
	} else {
		printf("received data\n");
		printf("%s\n", buf);
		break;
	}

	/* とりあえず一秒待ってみる */
	sleep(1);
 }

 close(sock);

 return 0;
}

ioctl関数の使い方はUDPとTCPで変わりません。 ここでは、説明のためにUDPソケットを利用しましたが、ioctlはTCPソケットでも利用できます。