免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 2122 | 回复: 0
打印 上一主题 下一主题

[C++] read函数返回值的困惑 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2013-06-13 22:50 |只看该作者 |倒序浏览
最近在学习《unix网络编程》,在第5章内容中有个例子:在客户与服务器之间传递二进制结构,让人百思不得其解的是为嘛在Readn函数中调用read函数读取数据时,直接返回0?客户端明明已经把数据write进去了,难道是木有flush,导致客户端套接字发送缓冲区中的数据根本木有发送给服务器?代码中省略了头文件包含,代码跟下面是客户端代码:

  1. #define MAXLINE 4096
  2. #define SERV_PORT 9875
  3. #define SA struct sockaddr

  4. struct args
  5. {
  6.         long arg1;
  7.         long arg2;
  8. };

  9. struct result
  10. {
  11.         long sum;
  12. };

  13. void print_errno()
  14. {
  15.         printf("stderr:%s\n",strerror(errno));
  16. }

  17. void err_quit(const char* err_msg)
  18. {
  19.         printf("%s",err_msg);
  20.         printf("\n");
  21.         return;
  22. }

  23. ssize_t Readn(int fd,void *vptr,size_t n)
  24. {
  25.         size_t nleft;
  26.         ssize_t nread;
  27.         char* ptr;
  28.         ptr = reinterpret_cast<char*>(vptr);
  29.         nleft = n;
  30.         while(nleft > 0)
  31.         {
  32.                 if((nread = read(fd,ptr,nleft) < 0))
  33.                 {
  34.                         if(errno == EINTR)
  35.                                 nread = 0;
  36.                         else
  37.                                 return -1;
  38.                 }else if(nread == 0)
  39.                         break;//EOF
  40.                 nleft -= nread;
  41.                 ptr += nread;
  42.         }
  43.         return n - nleft;

  44. }

  45. ssize_t Writen(int fd,const void *vptr,size_t n)
  46. {
  47.         size_t nleft;
  48.         ssize_t nwritten;
  49.         const char* ptr;

  50.         ptr = reinterpret_cast<const char*>(vptr);
  51.         nleft = n;
  52.         while(nleft > 0)
  53.         {
  54.                 if((nwritten = write(fd,ptr,nleft)) <= 0)
  55.                 {
  56.                         if(nwritten < 0 && errno == EINTR)
  57.                                 nwritten = 0;
  58.                         else
  59.                         {
  60.                                 print_errno();
  61.                                 return -1;
  62.                         }
  63.                 }
  64.                 nleft -= nwritten;
  65.                 ptr += nwritten;
  66.         }

  67.         return n - nleft;
  68. }

  69. void str_cli_new(FILE* fp,int sockfd)
  70. {
  71.         char sendline[MAXLINE];
  72.         struct args args;
  73.         struct result result;
  74.         while(fgets(sendline,MAXLINE,fp) != NULL)
  75.         {
  76.                 if(sscanf(sendline,"%ld%ld",&args.arg1,&args.arg2) != 2)
  77.                 {
  78.                         printf("invalid input:%s",sendline);
  79.                         continue;
  80.                 }
  81.                 printf("arg1:%ld arg2:%ld\n",args.arg1,args.arg2);
  82.                 Writen(sockfd,&args,sizeof(args));
  83.                 if(Readn(sockfd,&result,sizeof(result)) == 0)
  84.                         err_quit("str_cli:server terminated prematurely");
  85.                 printf("%ld\n",result.sum);
  86.         }
  87. }

  88. int main(int argc,char** argv)
  89. {
  90.         int sockfd;
  91.         struct sockaddr_in servaddr;
  92.         if(argc != 2)
  93.                 err_quit("usage:tcpcli<IPaddress>");

  94.         sockfd = socket(AF_INET,SOCK_STREAM,0);

  95.         bzero(&servaddr,sizeof(servaddr));
  96.         servaddr.sin_family = AF_INET;
  97.         servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
  98.         servaddr.sin_port = htons(SERV_PORT);
  99.         inet_pton(AF_INET,argv[1],&servaddr.sin_addr);

  100.         signal(SIGPIPE,SIG_IGN);

  101.         int res = connect(sockfd,(SA*)&servaddr,sizeof(servaddr));
  102.         printf("The result of connection is %d\n",res);
  103.         if(res < 0)
  104.                 printf("stderr:%s",strerror(errno));
  105.         str_cli_new(stdin,sockfd);
  106.         if(errno == EPIPE)
  107.                 printf("Broken pipe\n");
  108.         else
  109.                 printf("errno is %d",errno);
  110.         exit(0);
  111. }
复制代码
服务器代码:
  1. #define        MAXLINE                4096
  2. #define        LISTENQ                1024
  3. #define        SERV_PORT        9875
  4. #define SA struct sockaddr

  5. typedef void Sigfunc(int);

  6. void sig_chld(int signo);
  7. Sigfunc* signal(int signo,Sigfunc* func);

  8. struct args
  9. {
  10.         long arg1;
  11.         long arg2;
  12. };

  13. struct result
  14. {
  15.         long sum;
  16. };

  17. void err_sys(const char* err_msg)
  18. {
  19.         printf("%s",err_msg);
  20.         printf("\n");
  21.         exit(0);
  22. }

  23. void print_errno()
  24. {
  25.         printf("stderr:%s\n",strerror(errno));
  26. }

  27. ssize_t Readn(int fd,void *vptr,size_t n)
  28. {
  29.         size_t nleft;
  30.         ssize_t nread;
  31.         char* ptr;
  32.         printf("Readn begin here.\n");
  33.         ptr = reinterpret_cast<char*>(vptr);
  34.         nleft = n;
  35.         while(nleft > 0)
  36.         {
  37.                 if((nread = read(fd,ptr,nleft) < 0))
  38.                 {
  39.                         if(errno == EINTR)
  40.                         {
  41.                                 printf("EINTR error\n");
  42.                                 nread = 0;
  43.                         }
  44.                         else
  45.                         {
  46.                                 print_errno();
  47.                                 printf("error in function Readn\n");
  48.                                 return -1;
  49.                         }
  50.                 }else if(nread == 0)
  51.                 {
  52.                         printf("EOF");
  53.                         break;//EOF
  54.                 }
  55.                 nleft -= nread;
  56.                 ptr += nread;
  57.         }
  58.         return n - nleft;
  59. }

  60. ssize_t Writen(int fd,const void *vptr,size_t n)
  61. {
  62.         size_t nleft;
  63.         ssize_t nwritten;
  64.         const char* ptr;

  65.         ptr = reinterpret_cast<const char*>(vptr);
  66.         nleft = n;
  67.         while(nleft > 0)
  68.         {
  69.                 if((nwritten = write(fd,ptr,nleft)) <= 0)
  70.                 {
  71.                         if(nwritten < 0 && errno == EINTR)
  72.                                 nwritten = 0;
  73.                         else
  74.                         {
  75.                                 print_errno();
  76.                                 return -1;
  77.                         }
  78.                 }
  79.                 nleft -= nwritten;
  80.                 ptr += nwritten;
  81.         }

  82.         return n - nleft;
  83. }

  84. void str_echo_new(int sockfd)
  85. {
  86.         ssize_t n;
  87.         struct args args;
  88.         struct result result;
  89.         for(;;)
  90.         {
  91.                 if((n = Readn(sockfd,&args,sizeof(args))) == 0)
  92.                 {
  93.                         return;
  94.                 }
  95.                 printf("arg1:%ld arg2:%ld\n",args.arg1,args.arg2);
  96.                 result.sum = args.arg1 + args.arg2;
  97.                 Writen(sockfd,&result,sizeof(result));
  98.         }
  99. }

  100. int main()
  101. {
  102.         int listenfd,connfd;
  103.         pid_t childpid;
  104.         socklen_t clilen;
  105.         struct sockaddr_in cliaddr,servaddr;
  106.         listenfd = socket(AF_INET,SOCK_STREAM,0);
  107.         bzero(&servaddr,sizeof(servaddr));
  108.         servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
  109.         servaddr.sin_port = htons(SERV_PORT);
  110.         int bind_res = bind(listenfd,(SA*)&servaddr,sizeof(servaddr));
  111.         if(bind_res < 0)
  112.                 print_errno();

  113.         listen(listenfd,LISTENQ);
  114.         signal(SIGCHLD,sig_chld);
  115.         if(bind_res < 0)
  116.                 print_errno();

  117.         for(;;)
  118.         {
  119.                 clilen = sizeof(cliaddr);
  120.                 if((connfd = accept(listenfd,(SA*)&servaddr,&clilen)) < 0)
  121.                 {
  122.                         if(errno == EINTR)
  123.                                 continue;
  124.                         else
  125.                                 err_sys("accept error");
  126.                 }
  127.                 printf("An connection has been received.\n");
  128.                 if((childpid = fork()) == 0)
  129.                 {
  130.                         close(listenfd);
  131.                         str_echo_new(connfd);
  132.                         close(connfd);
  133.                         exit(0);
  134.                 }
  135.                 close(connfd);
  136.         }
  137. }
复制代码
代码跟书中的代码有点儿出入,不过结构基本上一样,启动服务器,然后启动客户端,命令行参数时127.0.0.1,可以发现服务器客户端连接成功,然后在客户端输入两个整数,回车,如果调试的可以发现write操作是成功的,也就是数据至少成功写入了套接字的发送缓冲区。不过服务器这边在fork子进程中,试图调用read操作去读取对应套接字接受缓冲区内容时,返回值为0,难道服务器响应套接字根本没有接收到数据?为什么呢?这个问题困扰小菜几天了,往各位大神不吝赐教哈
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP