求助:send函数本地发送,缓冲未满就EAGAIN错误

发布于 2022-09-03 19:44:36 字数 11509 浏览 18 评论 2

两个程序,一个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地址:

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <errno.h>
  4. #include <string.h>
  5. #include <sys/filio.h>
  6. #include <sys/types.h>
  7. #include <sys/socket.h>
  8. #include <netinet/in.h>
  9. #include <sys/time.h>        /* select */
  10. #include <netdb.h>
  11. #define MY_TEST_PORT         9011
  12. int main()
  13. {
  14.         int ret;
  15.         int s;
  16.         int ns;
  17.         struct sockaddr sa;
  18.         struct sockaddr dest;
  19.         struct sockaddr_in *sin;
  20.         socklen_t destlen;
  21.         fd_set rset;
  22.         int optval;
  23.         int optlen;
  24.         s = socket(AF_INET, SOCK_STREAM, 0);
  25.         if(s < 0)
  26.         {
  27.                 perror("socket:");
  28.                 exit(1);
  29.         }
  30.         sin = (struct sockaddr_in *) &sa;
  31.         sin->sin_family = AF_INET;
  32.         sin->sin_port = htons(MY_TEST_PORT);
  33.         sin->sin_addr.s_addr = INADDR_ANY;
  34.         ret = bind(s, &sa, sizeof(sa));
  35.         if(ret < 0)
  36.         {
  37.                 perror("bind:");
  38.                 exit(1);
  39.         }
  40.         optval = 1;
  41.         optlen = sizeof(optval);
  42.         /*set non-block */
  43.         do {
  44.                 ret = ioctl(s, FIONBIO, &optval);
  45.         } while(errno == EINTR);
  46.         optval = 64*1024;
  47.         optlen = sizeof(optval);
  48.         /*set recv buf size */
  49.         do {
  50.                 ret = setsockopt(s,SOL_SOCKET,SO_RCVBUF,&optval,optlen);
  51.         } while(errno == EINTR);
  52.         /*set send buf size */
  53.         do {
  54.                 ret = setsockopt(s,SOL_SOCKET,SO_SNDBUF,&optval,optlen);
  55.         } while(errno == EINTR);
  56.        
  57.         listen(s,5);
  58.         destlen = sizeof(dest);
  59.         while(1)
  60.         {
  61.                 FD_ZERO(&rset);
  62.                 FD_SET(s,&rset);
  63.                 select(s+1, &rset, NULL, NULL, NULL);
  64.                 if(FD_ISSET(s,&rset))
  65.                 {
  66.                         ns = accept(s, &dest, &destlen);
  67.                         printf("accept return %d errno %dn",ns,errno);
  68.                 }
  69.         }
  70. }

复制代码

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <sys/types.h>
  4. #include <sys/socket.h>
  5. #include <sys/time.h>        /* select */
  6. #include <errno.h>
  7. #include <stropts.h>
  8. #include <unistd.h>
  9. #include <sys/filio.h>
  10. #define MY_BUFFER_LEN         1024
  11. #define MY_TEST_PORT        9011
  12. #define MY_TEST_IP        "192.168.1.96"
  13. int main(int argc, char *argv[])
  14. {
  15.         int ret;
  16.         int s, ns;
  17.         int optval,optlen;
  18.         struct sockaddr sa;
  19.         struct sockaddr dest;
  20.         struct sockaddr_in *sin;
  21.        
  22.         int i;
  23.         char *buf = NULL;
  24.         int buflen;
  25.         if(argc == 2)
  26.         {
  27.                 buflen = atoi(argv[1]);
  28.                 if(buflen <= 0 || buflen > 64*1024)
  29.                 {
  30.                         buflen = 1024;
  31.                 }
  32.         }
  33.         else
  34.                 buflen = 1024;
  35.         buf = calloc(buflen,1);
  36.         setbuf(stdout,NULL);
  37.         s = socket(AF_INET, SOCK_STREAM, 0);
  38.        
  39.         optval = 1;
  40.         optlen = sizeof(optval);
  41.         /*set non-block */
  42.         do {
  43.                 ret = ioctl(s, FIONBIO, &optval);
  44.         } while(errno == EINTR);
  45.         optval = 64*1024;
  46.         optlen = sizeof(optval);
  47.         /*set recv buff size*/
  48.         do {
  49.                 ret = setsockopt(s,SOL_SOCKET,SO_RCVBUF,&optval,optlen);
  50.                 if(ret != 0 && errno != EINTR)
  51.                         printf("setsockopt11 ret %d errno %dn",ret,errno);
  52.         } while(errno == EINTR);
  53.         /*set send buff size*/
  54.         do {
  55.                 ret = setsockopt(s,SOL_SOCKET,SO_SNDBUF,&optval,optlen);
  56.                 if(ret != 0 && errno != EINTR)
  57.                         printf("setsockopt22 ret %d errno %dn",ret,errno);
  58.         } while(errno == EINTR);
  59.         sin = (struct sockaddr_in *) &dest;
  60.         memset(sin,0,sizeof(dest));
  61.         sin->sin_family = AF_INET;
  62.         sin->sin_port = htons(MY_TEST_PORT);
  63.         sin->sin_addr.s_addr = inet_addr(MY_TEST_IP);
  64.         ns = connect(s, &dest, sizeof(dest));
  65.         if(ns < 0)
  66.                 sleep(1);
  67.         for(i = 0; i < 0x7FFFFFFF; i++)
  68.         {
  69.                 ret = send(s, buf, buflen, 0 );
  70.                 if(ret < 0)
  71.                 {
  72.                         //printf("i %d ret %d errno %dn",i,ret,errno);
  73.                         printf("%dn",i);
  74.                         break;
  75.                 }
  76.         }
  77. }

复制代码

  1. #
  2. #
  3. #
  4. CC = gcc
  5. CFLAG = -g -c
  6. LDFLAG =
  7. LIBPATH = -lnsl -lsocket
  8. SRC_FILE = ${SRV_SRC_FILE} ${CLI_SRC_FILE}
  9. SRV_SRC_FILE = srv.c
  10. CLI_SRC_FILE = cli.c
  11. OBJ_FILE = ${SRV_OBJ_FILE} ${CLI_OBJ_FILE}
  12. SRV_OBJ_FILE = srv.o
  13. CLI_OBJ_FILE = cli.o
  14. BIN_FILE = ${SRV_BIN_FILE} ${CLI_BIN_FILE}
  15. SRV_BIN_FILE = srv
  16. CLI_BIN_FILE = cli
  17. all:
  18.         ${BIN_FILE}
  19. clean:
  20.         rm -f ${OBJ_FILE}
  21.         rm -f ${BIN_FILE}
  22. ${SRV_BIN_FILE} : ${SRV_OBJ_FILE}
  23.         ${CC} $^ -o $@ ${LDFLAG} ${LIBPATH}
  24. ${SRV_OBJ_FILE} : ${SRV_SRC_FILE}
  25.         ${CC} ${CFLAG} ${INCPATH} $^
  26. ${CLI_BIN_FILE} : ${CLI_OBJ_FILE}
  27.         ${CC} $^ -o $@ ${LDFLAG} ${LIBPATH}
  28. ${CLI_OBJ_FILE} : ${CLI_SRC_FILE}
  29.         ${CC} ${CFLAG} ${INCPATH} $^

复制代码

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

残花月 2022-09-11 00:37:07

的确如此,看来SunOS对回环的socket缓冲区有不同的处理,没有提供好控制参数接口。同样的代码在linux上运行则表现的符合逻辑。

飘落散花 2022-09-10 06:27:15

做一些补充:

user@test:~$uname -a
SunOS wfsrv 5.10 Generic_137138-09 i86pc i386 i86pc

在上面的测试中,减小发送包的大小一直到每次发送16或32字节,结果并没有发生变化,可见与缓冲大小无关的,

我用ndd /dev/tcp查看各种参数没发现有什么相关的

请大家多多指教,不知道的也可指点一下思路,谢谢了!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文