UDPによるデータの受信
(プログラムの概要)
ソケットを作成し、データを受信する簡単なサンプルプログラムを作成します。

/* * sample program * UDP Server program */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <getopt.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <netdb.h> #include <errno.h> #define UDPMAX 0xffff static void help(void); static int set_udp_socket(int, unsigned long); int main(int argc ,char *argv[]) { char buf[UDPMAX] = {0}; int opt = 0, sockfd = 0, port = 50000, loop = 1, len = 0; struct sockaddr_in from; socklen_t addrlen; const struct option longopt[] = { {"help", 0, 0, 'h'}, {"port", 1, 0, 'p'}, {0, 0, 0, 0}, }; /* get command option */ while((opt = getopt_long(argc, argv, "hHp:P:", longopt, NULL)) != -1){ switch(opt){ case 'p': case 'P': port = atoi(optarg); break; case 'h': case 'H': case '?': help(); return 0; } } if((port <= 0) || (port > 65535)){ help(); return -1; } /* create socket */ sockfd = set_udp_socket(port, 0); if(sockfd < 0){ return -1; } while(loop){ addrlen = sizeof(struct sockaddr_in); len = recvfrom(sockfd, buf, sizeof(buf), 0, (struct sockaddr *)&from, &addrlen); if(len < 0){ perror("recvfrom error"); break; }else if(addrlen == 0){ continue; /* unidentified address */ } fprintf(stdout, "received data(%dbyte) from %s:%d\n", len, inet_ntoa(from.sin_addr), ntohs(from.sin_port)); fprintf(stdout, "%s", buf); if(strncmp(buf, "quit\n", 5) == 0){ loop = 0; } memset(buf, 0, len); } close(sockfd); return 0; } static void help(void) { fprintf(stdout, "Usage: udpserver [-p port]\n" ); return; } static int set_udp_socket(int portnum, unsigned long ipaddr) { int sockfd; struct sockaddr_in server; /* create socket */ sockfd = socket(AF_INET, SOCK_DGRAM, 0); if(sockfd < 0){ perror("socket error"); return -1; } /* set socket address information */ memset(&server, 0, sizeof(struct sockaddr_in)); server.sin_family = AF_INET; if(ipaddr == 0){ server.sin_addr.s_addr = htonl(INADDR_ANY); }else{ server.sin_addr.s_addr = htonl(ipaddr); } server.sin_port = htons(portnum); /* bind socket */ if(bind(sockfd, (struct sockaddr *)&server, sizeof(server)) < 0){ perror("bind error"); close(sockfd); return -1; } return sockfd; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116

(プログラムの概要)
プログラム起動時の引数でポート番号を取得し、ソケットを作成し、指定したポート番号へのデータ到着を見張れるようにします。その後受信ループに入り、受信したデータを標準出力に表示します。

33L~49L:オプション分析
getopt_long()はコマンドラインオプションを解釈します。詳しくはgetoptのmanpageを参照してください。getopt_long()はgetopt()にプラスして、--で始まるオプションを解釈できるものです。
起動オプションを分析し、-pオプションがあればポート番号として値を取得します。-pオプションが無い場合はデフォルト値としてポート番号は50000になります。
52L~55L:ソケットの作成サブルーチン(詳細は下記参照)
57L~74L:受信ループ
recvfromはパケットが到着するまでスリープし、パケットが到着するとバッファに読み込みます。5番目の引数に送信元の情報が入れられるので、それを表示しています。

set_udp_socket()
ソケットを作成し、bindでは「第2引数のアドレス、ポート番号は、第1引数のソケットが接続を受け付けます。」という登録を行います。今回は引数ipaddrが0なのでINADDR_ANY(loや複数のNICがあれば全てのNICからの受信を受け付けます。)


(コンパイルと動作)
gcc -Wall -o sv udpserver.c
本プログラムを起動した状態で、前回作成した送信プログラムを動作させると、送信プログラムで入力したデータがサーバプログラムに表示されます。
サンプルプログラムではrecvfrom()を使ってデータが到着するまで待ちました、1つのポートを受信専用にするのであれば効率が良いのですが、1スレッドで2つのソケットを見張りたい場合があります。次回は少し受信処理を拡張します。