Path: sranha!katsu From: katsu@sra.co.jp (WATANABE Katsuhiro) Message-ID: Date: 5 Dec 90 12:13:20 Organization: Software Research Associates, Inc.,Japan In-reply-to: t-ishii@sra.co.jp's message of 27 Nov 90 06:55:06 GMT Newsgroups: sra.unix Subject: Re: TCP send buffer size Distribution: sra References: 渡邊です。やっぱり私の方の間違いみたいです。 記事 で t-ishii@sra.co.jp (Tatsuo Ishii) さんいはく > getsockopt() で SO_SNDBUF を取ってくると、たとえば NEWS OS R3.4 では > 4096 と出ます。これは、scoket に対し、1回の write() で 4096 バイトま > では送信してくれるという意味だと思っているのですが、果たしてこれは正し > いでしょうか? 限定された条件下での答えを見つけました。 「シグナルを捕捉する場合は、(SO_SNDBUF で返ってくる値などに関係なく) write() が途中で終ってしまうことがある」 というものです。(ローカルなディスクのファイルに write() する時は こんなこと起きませんよね?) 記事の最後に wt.c というテストプログラムをつけました。これは TCP の well known なサーバーに接続し、ひたすら write() を繰り返してその 返り値を監視するプログラムです。形式は wt [-i SIGNAL] [-s sbufsize] [-r rbufsize] [-x] service[@host] writesize となっていて、service は "echo", "discard" などのサービス名、writesize は write() の3番目の引数、-s と -r で SO_SNDBUF と SO_RCVBUF の値を設定 できます。さらに、-i INT などとすると、SIGINT を捕捉しますが、-i ALRM と すると特別で、SIGALRM を捕捉する上に1秒間隔のインターバルタイマを設定 します。-x は、write の返り値が writesize より小さかったら即終了させます。 そうそう、関係ないけど SO_DEBUG を指定してあります。実行すると最初の行に SO_SNDBUF と SO_RCVBUF の値を表示します。 そこで、 wt -i alrm discard@遠くの機械 4096 したり、 wt -i alrm -s 32768 discard 16384 したり、 root で inetd を renice 20 した後 wt -i alrm discard 4096 したり、 wt -i alrm echo 4096 すると、 SIGALRM を捕捉した直後に write() が中断されて戻ってきてしまっているのが 観察できます。これが SIGALRM に限ったことではないのは、wt -i all ... として ^C や ^Z を打ちまくるとわかります。 一般の場合(シグナルを捕捉しない場合)については相変わらず不明です。 ↓ 下はプログラムです。 #include #include #include #include #include #include #include #include #include #define PROTODEBUG #define ALARM_INTERVAL 1 extern char *malloc(); char *emalloc(), *strucpy(); int sighandle(); char *commandName; /* argv[0] */ int alarm; /* whether use interval timer or not */ static char *signame[] = { "0", "HUP", "INT", "QUIT", "ILL", "TRAP", "IOT", "EMT", "FPE", "KILL", "BUS", "SEGV", "SYS", "PIPE", "ALRM", "TERM", "URG", "STOP", "TSTP", "CONT", "CHLD", "TTIN", "TTOU", "IO", "XCPU", "XFSZ", "VTALRM", "PROF", "WINCH", "29", "USR1", "USR2"}; main(argc, argv) int argc; char **argv; { struct sockaddr_in server; struct servent *sp; struct hostent *hp; int s; int writeSize, writtenSize, recvBufSize, sendBufSize, sockoptSize; char *data; char *hostname, *servname; struct itimerval timer; #ifdef PROTODEBUG int debugOpt; #endif int xflag; int optionc; extern int optind; extern char *optarg; commandName = argv[0]; alarm = 0; xflag = 0; recvBufSize = sendBufSize = -1; while ((optionc = getopt(argc, argv, "xi:r:s:")) != EOF) { switch (optionc) { case 'x': xflag = 1; break; case 'i': setsignals(optarg); break; case 's': sendBufSize = atoi(optarg); break; case 'r': recvBufSize = atoi(optarg); break; case '?': default: usage(); exit(1); } } if (optind != argc - 2) { usage(); exit(1); } servname = emalloc(strlen(argv[optind]) + 1); strcpy(servname, argv[optind]); if ((hostname = index(servname, '@')) == (char *)NULL) { hostname = "localhost"; } else { *hostname++ = '¥0'; } if ((sp = getservbyname(servname, "tcp")) == (struct servent *)NULL) { fprintf(stderr, "%s: %s/tcp unknown service.¥n", commandName, servname); exit(2); } if ((hp = gethostbyname(hostname)) == (struct hostent *)NULL) { fprintf(stderr, "%s: %s: unknown host.¥n", commandName, hostname); exit(3); } free(servname); writeSize = atoi(argv[optind + 1]); bzero((char *)&server, sizeof(server)); bcopy(hp->h_addr, (char *)&server.sin_addr, hp->h_length); server.sin_family = hp->h_addrtype; server.sin_port = sp->s_port; if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) { eperror("socket()"); exit(11); } if (connect(s, (char *)&server, sizeof(server)) < 0) { eperror("connect()"); exit(12); } #ifdef PROTODEBUG debugOpt = 1; if (setsockopt(s, SOL_SOCKET, SO_DEBUG, (char *)debugOpt, sizeof(debugOpt)) < 0) { eperror("setsockopt(,,SO_DEBUG,,)"); exit(13); } #endif if (sendBufSize >= 0) { if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, (char *)&sendBufSize, sizeof(sendBufSize)) < 0) { eperror("setsockopt(,,SO_SNDBUF,,)"); exit(14); } } if (recvBufSize >= 0) { if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, (char *)&recvBufSize, sizeof(recvBufSize)) < 0) { eperror("setsockopt(,,SO_RCVBUF,,)"); exit(15); } } sockoptSize = sizeof(sendBufSize); if (getsockopt(s, SOL_SOCKET, SO_SNDBUF, (char *)&sendBufSize, &sockoptSize) < 0) { eperror("getsockopt(,,SO_SNDBUF,,)"); exit(16); } sockoptSize = sizeof(recvBufSize); if (getsockopt(s, SOL_SOCKET, SO_RCVBUF, (char *)&recvBufSize, &sockoptSize) < 0) { eperror("getsockopt(,,SO_RCVBUF,,)"); exit(17); } printf("sendBufSize:%d recvBufSize:%d¥n", sendBufSize, recvBufSize); data = emalloc(writeSize); if (alarm) { timer.it_interval.tv_sec = ALARM_INTERVAL; timer.it_interval.tv_usec = 0; timer.it_value.tv_sec = ALARM_INTERVAL; timer.it_value.tv_usec = 0; setitimer(ITIMER_REAL, &timer, (struct itimerval *)0); } while (1) { printf("Trying to write(,,%d)...", writeSize); fflush(stdout); writtenSize = write(s, data, writeSize); printf("%d chars written.¥n", writtenSize); fflush(stdout); if ((writtenSize < writeSize) && xflag) { fprintf(stderr, "%s: write() is given up.¥n", commandName); exit(128); } } } sighandle(sig) int sig; { fprintf(stderr, "SIG%s is caught...", signame[sig]); fflush(stderr); } eperror(errFunc) char *errFunc; { fprintf(stderr, "%s: ", commandName); perror(errFunc); } usage() { fprintf(stderr, "Usage:%s [-i SIGNAL] [-s sbufsize] [-r rbufsize] [-x] service[@host] writesize¥n", commandName); } setsignals(name) char *name; { int i; char *uname; uname = emalloc(strlen(name) + 1); strucpy(uname, name); if (!(strcmp(uname, "ALL"))) { for (i = 1; i < NSIG; i++) { signal(i, sighandle); /* if (i == SIGALRM) { alarm = 1; } */ } } else { for (i = 1; i < NSIG; i++) { if (!(strcmp(uname, signame[i]))) { signal(i, sighandle); if (i == SIGALRM) { alarm = 1; } free(uname); return; } } fprintf(stderr, "%s: illegal signal name. (should be 'ALL' or one of `kill -l`)¥n", commandName); exit(1); } free(uname); } /* make a capitalized copy of src */ char *strucpy(dest, src) char *dest, *src; { char *p; p = dest; do { if (islower(*src)) { *p++ = toupper(*src); } else { *p++ = *src; } } while (*src++); return dest; } /* malloc with error handling */ char *emalloc(size) unsigned size; { char *ptr; if ((ptr = malloc(size)) == (char *)NULL) { fprintf(stderr, "%s: cannot allocate memory.¥n", commandName); exit(9); } return ptr; } -- ----____----____ 渡邊克宏@ソフトウェア工学研旧所