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

/* * sample program * UDP Client 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 BUFSIZE 1024 static void help(void); int main(int argc ,char *argv[]) { char host[256] = {0}; char buf[BUFSIZE] = {0}; char portnum[8] = {0}; struct sockaddr_in sv; struct addrinfo hints, *res; int opt = 0, sockfd = 0, port = 50000, len = 0, ret = 0; 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; }else{ snprintf(portnum, sizeof(portnum), "%d", port); } /* get hostname or ipaddr */ if(optind >= argc){ help(); return -1; } strncpy(host, argv[optind], 256); memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_family = AF_INET; hints.ai_socktype = SOCK_DGRAM; hints.ai_flags = 0; hints.ai_protocol = 0; ret = getaddrinfo(host, portnum, &hints, &res); if((ret != 0) || (res == NULL)){ fprintf(stdout, "server not found!\n"); return -1; } /* set destination address */ memcpy(&sv, res->ai_addr, sizeof(struct sockaddr_in)); freeaddrinfo(res); fprintf(stdout, "send message to %s:%d\n", inet_ntoa(sv.sin_addr), ntohs(sv.sin_port)); /* create socket */ sockfd = socket(AF_INET, SOCK_DGRAM, 0); if(sockfd < 0){ perror("socket error"); return -1; } while(1){ memset(buf, 0, BUFSIZE); read(STDIN_FILENO, buf, BUFSIZE -1); len = strlen(buf); len = sendto(sockfd, buf, len, 0, (struct sockaddr *)&sv, sizeof(sv)); if(len < 0){ perror("sendto error"); }else{ fprintf(stdout, "send %d byte\n", len); } if(strncmp(buf, "quit\n", 5) == 0){ break; } } close(sockfd); return 0; } static void help(void) { fprintf(stdout, "Usage: udpclient [-p port] destination\n" ); return; }
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

(プログラムの概要)
プログラム起動時の引数で送信先のアドレスとポート番号を取得し、キーボードからの入力をUDPパケットとして宛先に送信します。

34L~52L:オプション分析
getopt_long()はコマンドラインオプションを解釈します。詳しくはgetoptのmanpageを参照してください。getopt_long()はgetopt()にプラスして、--で始まるオプションを解釈できるものです。
起動オプションを分析し、-pオプションがあればポート番号として値を取得します。-pオプションが無い場合はデフォルト値としてポート番号は50000になります。
55L~59L:引数取得
コマンド引数として宛先を取得します。宛先はホスト名またはIPアドレスです。
60L~74L:宛先のアドレス解決
getaddrinfo()を使用して、ホスト名からIPアドレスに変換します。文字列が元々IPアドレスの場合もIPアドレスが求められます。今回はAF_INETと言うことで、IPv4に限定しています。getaddrinfo()は成功すると動的にメモリを割り当てるので、必ずfreeaddrinfo()でメモリを解放します。
77L~81L:ソケット作成
送信に使用するソケットを作成します。
83L~96L:入力データを送信
標準入力から取得したデータを、sendto()を使用して送信しています。


(コンパイルと動作)
gcc -Wall -g -o udpclient udpclient.c
プログラム上でデータを送信できているかを見ることはできませんが、tcpdumpやwireshark等のパケットキャプチャを使用して実際にネットワーク上に送信されているかを確認できます。
次回はサーバ側プログラムを作成し、送信されてきたデータを表示できるようにします。