UNIXネットワークプログラミングのお勉強 (3) PF_UNIX vs. PF_INET
そういえば一か月前はネットワークプログラミングを勉強していたことを思い出した.案の定,すべてを忘れていたのでもう一度復習.
マシン内の通信の場合,TCP通信 (PF_INET) 以外にファイルを介したソケット通信 (PF_UNIX) という選択肢がある.どれくらいパフォーマンスが違うのだろうと思って,PF_UNIXとPF_INETでかかる時間を計測してみた.
実験条件
-
- server, clientの1対1通信
- connectし終わってから100万send/recvにかかる時間を計測
- 一回の通信で送信されるデータサイズを変更して比較 (64,1024,8192,16384,32768bytes)
- 時間計測はgettimeofdayを使用
- 各10回試行して平均を算出
結果
表のsizeはbyte.各方式の値は平均時間 (sec.).
- 基本的にPF_INETの方が速い.ディスクI/Oで時間かかっていると思われる.
- straceで確認したところ,システムコール的な違いはなさそう.
- データサイズが8192bytesの場合,PF_INETにおいて急に時間がかかるようになった!
- おかしいと思って,何回もやりなおしたところ,平均はあまり変化ないものの,分散が非常に大きいという結果になった.
- パケットサイズが関係しているのかもしれないが,詳しい原因はわからないので放置.
まとめ
ネットワークプログラミングはTCP (PF_INET) でいいんじゃない?
Appendix
PF_UNIXに用いたソースコード.PF_INETもソケット作成部分以外,基本的に同じ
server.c
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/un.h> #include <sys/types.h> #include <sys/socket.h> #define SERVER "sock_s" #define BUFFLEN 40960 int main (int argc, char *argv[]) { int soc; if ((soc = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) { perror("socket"); exit(1); } struct sockaddr_un sun; sun.sun_family = AF_UNIX; strcpy(sun.sun_path, SERVER); int len = sizeof(sun.sun_family) + strlen(sun.sun_path); if (bind(soc, (struct sockaddr *)&sun, len) < 0) { perror("bind"); exit(1); } if (listen(soc, 5) < 0) { perror("listen"); exit(1); } int fd; int sunlen = sizeof(sun); char buff[BUFFLEN]; for (;;) { if ((fd = accept(soc, (struct sockaddr *)&sun, (socklen_t *)&sunlen)) < 0) { perror("accept"); exit(1); } while (recv(fd, buff, BUFFLEN, 0) > 0) { // printf("Received message: %s\n", buff); } close(fd); } close(soc); unlink(SERVER); return 0; }
client.c
#include <stdio.h> #include <stdlib.h> #include <sys/socket.h> #include <sys/types.h> #include <sys/un.h> #include <unistd.h> #include <string.h> #include <sys/time.h> #define SERVER "sock_s" #define BUFFLEN 40960 #define DATASIZE 64 double gettimeofday_sec (void) { struct timeval tv; gettimeofday(&tv, NULL); return tv.tv_sec + (double)tv.tv_usec * 1e-6; } int main (void) { int soc; if ((soc = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) { perror("socket"); exit(1); } struct sockaddr_un sun; sun.sun_family = AF_UNIX; strcpy(sun.sun_path, SERVER); int len = sizeof(sun.sun_family) + strlen(sun.sun_path); if (connect(soc, (struct sockaddr *)&sun, len) < 0) { perror("connect"); exit(1); } char buff[BUFFLEN]; // strcpy(buff, "HELLO"); memset(buff, 'a', DATASIZE); buff[ DATASIZE ] = '\0'; int i; int loop = 1000000; double begin = gettimeofday_sec(); for (i = 0; i < loop; i++) { if (send(soc, buff, strlen(buff) + 1, 0) < 0) { perror("send"); exit(1); } } double end = gettimeofday_sec(); // printf("time=%lf sec\n", end - begin); printf("%lf\n", end - begin); shutdown(soc, SHUT_RDWR); close(soc); return 0; }