求助:send函数本地发送,缓冲未满就EAGAIN错误
两个程序,一个srv,一个cli,建立tcp连接后,cli 程序连续不断地发送指定大小的数据到srv程序,而srv程序不做任何接收
最后统计cli连续发送多少包后开始发送失败(返回-1,错误码为 EAGAIN)。
在我的测试中,在每次发的数据包的大小1024的情况下,
当srv与cli在同一主机上运行时,结果从8到30变化不定,这远远小于事先指定的缓冲大小64k
当srv与cli在不同主机上运行时,结果是固定的,一般约为缓冲大小/发送包大小,这个很容易理解
不解为什么两者在同一主机上运行时,会出现这种情况,
在我的应用中,由于客户端发送包小但短时间会发送很多包,server端接收处理不够及时,所以设置了较大的缓冲,
没想到在同一台机器上运行时缓冲没使用完就发送失败了
下面为我的测试程序,请大家多多指教!!!
代码如下,前面的是srv.c,后面的为cli.c,最后为Makefile,方便大家测试,测试时需修改cli.c中宏MY_TEST_IP指定的IP地址:
- #include <stdio.h>
- #include <stdlib.h>
- #include <errno.h>
- #include <string.h>
- #include <sys/filio.h>
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <sys/time.h> /* select */
- #include <netdb.h>
- #define MY_TEST_PORT 9011
- int main()
- {
- int ret;
- int s;
- int ns;
- struct sockaddr sa;
- struct sockaddr dest;
- struct sockaddr_in *sin;
- socklen_t destlen;
- fd_set rset;
- int optval;
- int optlen;
- s = socket(AF_INET, SOCK_STREAM, 0);
- if(s < 0)
- {
- perror("socket:");
- exit(1);
- }
- sin = (struct sockaddr_in *) &sa;
- sin->sin_family = AF_INET;
- sin->sin_port = htons(MY_TEST_PORT);
- sin->sin_addr.s_addr = INADDR_ANY;
- ret = bind(s, &sa, sizeof(sa));
- if(ret < 0)
- {
- perror("bind:");
- exit(1);
- }
- optval = 1;
- optlen = sizeof(optval);
- /*set non-block */
- do {
- ret = ioctl(s, FIONBIO, &optval);
- } while(errno == EINTR);
- optval = 64*1024;
- optlen = sizeof(optval);
- /*set recv buf size */
- do {
- ret = setsockopt(s,SOL_SOCKET,SO_RCVBUF,&optval,optlen);
- } while(errno == EINTR);
- /*set send buf size */
- do {
- ret = setsockopt(s,SOL_SOCKET,SO_SNDBUF,&optval,optlen);
- } while(errno == EINTR);
- listen(s,5);
- destlen = sizeof(dest);
- while(1)
- {
- FD_ZERO(&rset);
- FD_SET(s,&rset);
- select(s+1, &rset, NULL, NULL, NULL);
- if(FD_ISSET(s,&rset))
- {
- ns = accept(s, &dest, &destlen);
- printf("accept return %d errno %dn",ns,errno);
- }
- }
- }
复制代码
- #include <stdio.h>
- #include <stdlib.h>
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <sys/time.h> /* select */
- #include <errno.h>
- #include <stropts.h>
- #include <unistd.h>
- #include <sys/filio.h>
- #define MY_BUFFER_LEN 1024
- #define MY_TEST_PORT 9011
- #define MY_TEST_IP "192.168.1.96"
- int main(int argc, char *argv[])
- {
- int ret;
- int s, ns;
- int optval,optlen;
- struct sockaddr sa;
- struct sockaddr dest;
- struct sockaddr_in *sin;
- int i;
- char *buf = NULL;
- int buflen;
- if(argc == 2)
- {
- buflen = atoi(argv[1]);
- if(buflen <= 0 || buflen > 64*1024)
- {
- buflen = 1024;
- }
- }
- else
- buflen = 1024;
- buf = calloc(buflen,1);
- setbuf(stdout,NULL);
- s = socket(AF_INET, SOCK_STREAM, 0);
- optval = 1;
- optlen = sizeof(optval);
- /*set non-block */
- do {
- ret = ioctl(s, FIONBIO, &optval);
- } while(errno == EINTR);
- optval = 64*1024;
- optlen = sizeof(optval);
- /*set recv buff size*/
- do {
- ret = setsockopt(s,SOL_SOCKET,SO_RCVBUF,&optval,optlen);
- if(ret != 0 && errno != EINTR)
- printf("setsockopt11 ret %d errno %dn",ret,errno);
- } while(errno == EINTR);
- /*set send buff size*/
- do {
- ret = setsockopt(s,SOL_SOCKET,SO_SNDBUF,&optval,optlen);
- if(ret != 0 && errno != EINTR)
- printf("setsockopt22 ret %d errno %dn",ret,errno);
- } while(errno == EINTR);
- sin = (struct sockaddr_in *) &dest;
- memset(sin,0,sizeof(dest));
- sin->sin_family = AF_INET;
- sin->sin_port = htons(MY_TEST_PORT);
- sin->sin_addr.s_addr = inet_addr(MY_TEST_IP);
- ns = connect(s, &dest, sizeof(dest));
- if(ns < 0)
- sleep(1);
- for(i = 0; i < 0x7FFFFFFF; i++)
- {
- ret = send(s, buf, buflen, 0 );
- if(ret < 0)
- {
- //printf("i %d ret %d errno %dn",i,ret,errno);
- printf("%dn",i);
- break;
- }
- }
- }
复制代码
- #
- #
- #
- CC = gcc
- CFLAG = -g -c
- LDFLAG =
- LIBPATH = -lnsl -lsocket
- SRC_FILE = ${SRV_SRC_FILE} ${CLI_SRC_FILE}
- SRV_SRC_FILE = srv.c
- CLI_SRC_FILE = cli.c
- OBJ_FILE = ${SRV_OBJ_FILE} ${CLI_OBJ_FILE}
- SRV_OBJ_FILE = srv.o
- CLI_OBJ_FILE = cli.o
- BIN_FILE = ${SRV_BIN_FILE} ${CLI_BIN_FILE}
- SRV_BIN_FILE = srv
- CLI_BIN_FILE = cli
- all:
- ${BIN_FILE}
- clean:
- rm -f ${OBJ_FILE}
- rm -f ${BIN_FILE}
- ${SRV_BIN_FILE} : ${SRV_OBJ_FILE}
- ${CC} $^ -o $@ ${LDFLAG} ${LIBPATH}
- ${SRV_OBJ_FILE} : ${SRV_SRC_FILE}
- ${CC} ${CFLAG} ${INCPATH} $^
- ${CLI_BIN_FILE} : ${CLI_OBJ_FILE}
- ${CC} $^ -o $@ ${LDFLAG} ${LIBPATH}
- ${CLI_OBJ_FILE} : ${CLI_SRC_FILE}
- ${CC} ${CFLAG} ${INCPATH} $^
复制代码
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
的确如此,看来SunOS对回环的socket缓冲区有不同的处理,没有提供好控制参数接口。同样的代码在linux上运行则表现的符合逻辑。
做一些补充:
user@test:~$uname -a
SunOS wfsrv 5.10 Generic_137138-09 i86pc i386 i86pc
在上面的测试中,减小发送包的大小一直到每次发送16或32字节,结果并没有发生变化,可见与缓冲大小无关的,
我用ndd /dev/tcp查看各种参数没发现有什么相关的
请大家多多指教,不知道的也可指点一下思路,谢谢了!