Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2112725
  • 博文数量: 438
  • 博客积分: 3871
  • 博客等级: 中校
  • 技术积分: 6075
  • 用 户 组: 普通用户
  • 注册时间: 2011-09-10 00:11
个人简介

邮箱: wangcong02345@163.com

文章分类

全部博文(438)

文章存档

2017年(15)

2016年(119)

2015年(91)

2014年(62)

2013年(56)

2012年(79)

2011年(16)

分类: LINUX

2015-06-15 10:29:33

1. 异常描述
a. client 连接到server之后,server fork一个child,正常通信
b. kill child,这会导致
   TCP:
      server--->FIN-->client
      client--->ACK-->server
c.   Server内部
      SIGCHLD --> parent --> waitpid --> 子进程终止
d.  Clienet内部
     一直阻塞在fgets函数上,不知道server己经终止
e. 一句话总结问题
     当client阻塞在fgets函数上时,socket有情况,fgets只能处理用户输入处理不了socket,导致异常

2. 源码

client.c
  1. cong@msi:/work/test/tcpip/11select/client$ cat client.c
  2. #include "utils.h"

  3. //#define TIME_SERV_ADDR "192.168.4.98"
  4. #define TIME_SERV_ADDR "127.0.0.1"

  5. ssize_t readline(int fd, void* vptr, size_t maxlen)
  6. {
  7.     ssize_t n, rc;
  8.     char c,*ptr;
  9.     ptr = vptr;
  10.     for(n=0; n<maxlen; n++)
  11.     {
  12. again:
  13.         if( (rc=read(fd,&c,1)) == 1)  //readline实际上是readb阻塞
  14.         {
  15.             *ptr++ = c;
  16.             if(c == '\n')
  17.                 break;
  18.         } else if(rc == 0) {
  19.             *ptr = 0;
  20.             return n;
  21.         }else {
  22.             if( errno == EINTR)
  23.                 goto again;
  24.             return -1;
  25.         }
  26.     }
  27.     *ptr = '\0';
  28.     return n;
  29. }

  30. #if 0
  31. void str_cli(FILE* fp, int sockfd)
  32. {
  33.     char sendline[MAXLINE], recvline[MAXLINE];
  34.     while(fgets(sendline, MAXLINE, fp) != NULL)   //阻塞在fgets上时,只能处理stdin,当socket再有变化时,就搞不定了
  35.     {
  36.         write(sockfd, sendline, strlen(sendline));

  37.         if(readline(sockfd, recvline, MAXLINE) == 0)
  38.             dbmsg("server terminated");
  39.         fputs(recvline, stdout);
  40.     }

  41. }
  42. #endif
  43. void str_cli(FILE* fp, int sockfd)
  44. {
  45.     int maxfdp1,ret;
  46.     fd_set rset;
  47.     char sendline[MAXLINE], recvline[MAXLINE];
  48.     FD_ZERO(&rset);
  49.     while(1)
  50.     {
  51.         FD_SET(fileno(fp), &rset);
  52.         FD_SET(sockfd, &rset);
  53.         maxfdp1 = max(fileno(fp), sockfd)+1;
  54.         //dbmsg("fd=%d,sockfd=%d,maxfdp1=%d",fileno(fp), sockfd, maxfdp1);
  55.         ret = select(maxfdp1, &rset, NULL, NULL, NULL);  //改进程序,一直轮询stdin与socket,哪个有变化就处理哪个
  56.         if(ret <= 0)
  57.             continue;
  58.         if(FD_ISSET(sockfd, &rset))                    //socket有变化就处理socket
  59.         {
  60.             if( (readline(sockfd, recvline, MAXLINE)) == 0)
  61.                 dbmsg("server terminated");
  62.             fputs(recvline, stdout);
  63.         }
  64.         if(FD_ISSET(fileno(fp),&rset))                  //stdin有变化就处理stdin
  65.         {
  66.             if(fgets(sendline, MAXLINE, fp) == NULL)
  67.                 return;
  68.             write(sockfd, sendline, strlen(sendline));
  69.         }
  70.     }
  71. }

  72. int main ( int argc, char *argv[] )
  73. {
  74.     int i;
  75.     int sockfd, n;
  76.     struct sockaddr_in servaddr;
  77.     char recvline[1024];
  78.     sockfd = socket(AF_INET, SOCK_STREAM, 0);
  79.     if(sockfd < 0)
  80.         return -1;
  81.     bzero(&servaddr, sizeof(servaddr));
  82.     servaddr.sin_family = AF_INET;
  83.     servaddr.sin_port = htons(13999);
  84.     inet_pton(AF_INET, TIME_SERV_ADDR, &servaddr.sin_addr);
  85.     if( connect(sockfd, (const struct sockaddr*)&servaddr, sizeof(servaddr))< 0)
  86.         return -1;
  87.     dbmsg("connect success");
  88.     str_cli(stdin, sockfd);
  89.     return EXIT_SUCCESS;
  90. }

3. 附件
serv.rar (下载后改名为server.tar.gz)

client.rar (下载后改名为client.tar.gz)
阅读(1059) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~