2月
22
BSDソケットインターフェースの話ですが。
ファイルディスクリプタをノンブロッキングに設定すると、読めるデータがない(受信バッファにデータがない)場合は read() / recv() から -1 が返ってきて、errno が EAGAIN に設定されます。一方これとは別に、ソケットに対して recv() する場合、第4引数(フラグ)に MSG_WAITALL を指定すると、第3引数で指定した分だけ読めるまで返ってきません(基本的には)。
じゃあ両方やるとどうなるの?というわけで以下のテストプログラム。
#include <sys/ioctl.h> #include <sys/socket.h> #include <errno.h> #include <netdb.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <netinet/in.h> int main(int argc, char **argv) { struct addrinfo *ai; int fd; int on = 1; char buf[1000]; ssize_t n; getaddrinfo(argv[1], argv[2], NULL, &ai); fd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); ioctl(fd, FIONBIO, &on); connect(fd, ai->ai_addr, ai->ai_addrlen); sleep(1); errno = 0; n = recv(fd, buf, 1000, MSG_WAITALL); printf("ret=%d errno=%d %s\n", n, errno, strerror(errno)); return 0; }
これで適当なサーバにつないで動作を見ます。sleep() が挟まっているのは、受信バッファにデータが溜まるのを待つためです。SMTPサーバはサーバから話し始めるので、データが溜まり、HTTPサーバはクライアントから話し始めるのでデータは溜まりません。
まず CentOS 5 (kernel-2.6.18-194.32.1.el5) での実行例。
[umezawa@nyx:pts/1 ~]$ ./recv_nonblocking_waitall localhost 25 ret=29 errno=0 Success [umezawa@nyx:pts/1 ~]$ ./recv_nonblocking_waitall localhost 80 ret=-1 errno=11 Resource temporarily unavailable [umezawa@nyx:pts/1 ~]$
どうやらノンブロッキング指定のほうが「一方的に強い」ようで、MSG_WAITALL が指定されていないのと同じ挙動になります。
一方、FreeBSD 8.1-RELEASE では
[umezawa@devfreebsd ~]$ ./recv_nonblocking_waitall localhost 25 ret=-1 errno=35 Resource temporarily unavailable [umezawa@devfreebsd ~]$ ./recv_nonblocking_waitall nyx.local 80 ret=-1 errno=35 Resource temporarily unavailable [umezawa@devfreebsd ~]$
となり、ノンブロッキングの指定と MSG_WAITALL の指定が矛盾なく組み合わさっている…つまり、指定した分だけ読めない場合は即座に EAGAIN で失敗するように見えます。
結論としては「移植性がないので使わないほうがいい」というところに落ち着きそうです。以上、誰得情報でした(ぁ
no comment untill now