免费注册 查看新帖 |

Chinaunix

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

[C] 为什么socket接收到的是上个客户端送的数据,贴代码 [复制链接]

论坛徽章:
1
15-16赛季CBA联赛之深圳
日期:2016-02-17 16:12:23
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2014-02-14 15:24 |只看该作者 |倒序浏览
本帖最后由 lewy7 于 2014-02-15 21:02 编辑

现在碰到个问题,
当客户端a  在与服务短s 通信过中异常断开后,再有新客户端b连接进来的时候,会读到上个客户端a的发数据,而不是读到客户端b的发数据。

如果再有客户端c连接到服务端s的时候,读到的又是客户端b发送的数据。

还有一个更棘手的问题,当出现上面这种情况的时候,服务端会出现CLOSE_WAIT,并且持续很久,而且新连接进来的客户端有很大几率连接不进服务端。

这一般是什么原因,怎么处理?
有哪位帮看一下,感激不尽



贴代码
  1. #define LISTEN_BACKLOG    511
  2. #define  EPOLL_MAX_EVENTS  1000
  3. #define  EPOLL_TIMEOUT    500
  4. #define  EPOLL_SIZE       1024
  5. #define  BIG_BUFF_SIZE       4096
  6. #define  CONTENT_LEN                                 10 //长度信息所占长度

  7. typedef struct ep_container_s ep_container_t;
  8. struct ep_container_s
  9. {
  10.     int   fd;
  11.     char  ibuf[BIG_BUFF_SIZE];
  12.     char  obuf[BIG_BUFF_SIZE];
  13.     int   ilen;
  14.     int   ioffset;
  15.     int   olen;
  16.     int  ooffset;
  17. };



  18. void ms_tcp_working()
  19. {
  20.         int epollfd;
  21.         int fds;
  22.         int sfd;
  23.         int clientfd;
  24.         int i,ret;
  25.         int errinfo;
  26.         int cork;
  27.         struct linger so_linger;
  28.         struct epoll_event ev,events[EPOLL_MAX_EVENTS];
  29.         ep_container_t   ep_c;
  30.     ep_container_t  *ep_c_ptr;
  31.    
  32.      epollfd=epoll_create(EPOLL_SIZE);
  33.            ev.data.fd=_tcp_param.listenfd;
  34.            ev.events=EPOLLIN|EPOLLET;
  35.            epoll_ctl(epollfd,EPOLL_CTL_ADD,_tcp_param.listenfd,&ev);
  36.            
  37.          while(1)
  38.          {
  39.             fds=epoll_wait(epollfd,events,EPOLL_MAX_EVENTS,EPOLL_TIMEOUT);
  40.             for(i=0;i<fds;++i)
  41.             {
  42.                       if(events[i].data.fd == _tcp_param.listenfd)
  43.                       {
  44.                               printf("client connect\n");
  45.                         clientfd = accept(_tcp_param.listenfd,NULL,NULL);
  46.                         if(clientfd<0 )
  47.                         {
  48.                                 if(EAGAIN==errno)//忽略惊群
  49.                                 {
  50.                                         printf("EAGAIN%d\n",getpid());
  51.                                         continue;
  52.                                 }
  53.                                 else
  54.                                 {
  55.                                         perror("accept err:");
  56.                                         exit(1);
  57.                                 }
  58.                         }
  59.                         ms_tcp_set_nonblocking(clientfd);//设置非阻塞
  60.                         so_linger.l_onoff = 1;
  61.                                 so_linger.l_linger = 2;
  62.                                 setsockopt(clientfd,SOL_SOCKET,SO_LINGER,&so_linger,sizeof(struct linger));
  63.                         printf("clientfd=[%d]\n",clientfd);
  64.                         //添加用于读操作的文件描述符
  65.                         ep_c_ptr=(ep_container_t *)malloc(sizeof(ep_container_t));
  66.                         ep_c_ptr->fd = clientfd;
  67.                         ep_c_ptr->ioffset = 0;//记录已经收到客户端发送的字节数
  68.                         ep_c_ptr->ilen = 0;//记录接收 头部10个字节的长度信息
  69.                         ep_c_ptr->olen = 0;
  70.                         ep_c_ptr->ooffset = 0;
  71.                         ev.data.ptr = ep_c_ptr;
  72.                         ev.events=EPOLLIN|EPOLLET;
  73.                         ret = epoll_ctl(epollfd,EPOLL_CTL_ADD,clientfd,&ev);
  74.                       }
  75.                       else if(events[i].events&EPOLLIN)
  76.                       {
  77.                               printf("EPOLLIN\n");
  78.                         ep_c_ptr = (ep_container_t *)events[i].data.ptr;
  79.                         sfd = ep_c_ptr->fd;
  80.                         while(1)//本次循环读取,一直读到EAGAIN
  81.                         {
  82.                                 printf("rr ep_c_ptr->ioffset=[%d]\n",ep_c_ptr->ioffset);
  83.                                         ret = read(sfd, ep_c_ptr->ibuf+ep_c_ptr->ioffset, BIG_BUFF_SIZE);
  84.                                         if(0 == ret || -1 == ret && errno == EAGAIN || -1 == ret && errno == ECONNRESET || -1 == ret &&errno==ETIMEDOUT)
  85.                                         {
  86.                                                 errinfo = errno;
  87.                                                 break;
  88.                                         }
  89.                                         if(ret >0)
  90.                                         {
  91.                                                 ep_c_ptr->ioffset +=         ret;
  92.                                                 continue;
  93.                                         }
  94.                         }
  95.                         if(ECONNRESET == errinfo && -1 == ret || 0 ==ret || -1 == ret &&errinfo==ETIMEDOUT)
  96.                         {
  97.                                         free(events[i].data.ptr);
  98.                             events[i].data.ptr = NULL;
  99.                             epoll_ctl(epollfd,EPOLL_CTL_DEL,sfd,NULL);
  100.                             printf("close-----[%d][%d]ret[%d]\n",getpid(),sfd,ret);
  101.                             close(sfd);
  102.                             continue;
  103.                         }
  104.                         else if (-1 == ret && errinfo == EAGAIN )//本次读取 完毕
  105.                         {
  106.                                 if( 0 == ep_c_ptr->ilen)//取头部长度信息
  107.                                 {
  108.                                         ep_c_ptr->ilen =         ms_tcp_leninfo(ep_c_ptr->ibuf);
  109.                                 }
  110.                                 if(ep_c_ptr->ilen > ep_c_ptr->ioffset+CONTENT_LEN)
  111.                                 {
  112.                                         //继续将文件描述符加入可读事件队列
  113.                                         printf("cc ep_c_ptr->ioffset=[%d]\n",ep_c_ptr->ioffset);
  114.                                         ev.data.ptr = ep_c_ptr;
  115.                                         ev.events=EPOLLIN|EPOLLET;
  116.                                         if(-1 == epoll_ctl(epollfd,EPOLL_CTL_MOD,sfd,&ev))
  117.                                         {
  118.                                                 perror("epoll_ctl err:EPOLL_CTL_MOD");
  119.                                                 free(ep_c_ptr);
  120.                                                 close(sfd);
  121.                                         }
  122.                            }
  123.                            else
  124.                            {
  125.                                            printf("pid%drecv=[%d][%d][%s]\n",getpid(),ep_c_ptr->ilen,ep_c_ptr->ioffset,ep_c_ptr->ibuf);
  126.                                                 //将文件描述符加入可写事件队列
  127.                                         ev.data.ptr = ep_c_ptr;
  128.                                         ev.events=EPOLLOUT|EPOLLET;
  129.                                         if(-1 == epoll_ctl(epollfd,EPOLL_CTL_MOD,sfd,&ev))
  130.                                         {
  131.                                                 perror("epoll_ctl err:EPOLL_CTL_MOD");
  132.                                                 free(ep_c_ptr);
  133.                                                 close(sfd);
  134.                                         }
  135.                            }
  136.                            continue;//继续循环
  137.                                        
  138.                         }
  139.                 }
  140.                 else if(events[i].events&EPOLLOUT)
  141.                 {
  142.                         printf("EPOLLOUT\n");
  143.                         ep_c_ptr = (ep_container_t *)events[i].data.ptr;
  144.                         sfd = ep_c_ptr->fd;
  145.                         strcpy(ep_c_ptr->obuf,"0000000005aaaax");
  146.                         if(ep_c_ptr->ooffset == 0)
  147.                                 ep_c_ptr->olen=5;
  148.         
  149.                         ret=write(sfd, ep_c_ptr->obuf+ep_c_ptr->ooffset, ep_c_ptr->olen+CONTENT_LEN);

  150.                                 if(ret>0)
  151.                                 {
  152.                                         printf("write[%d]\n",ret);
  153.                                         ep_c_ptr->ooffset += ret;
  154.                                         if(ep_c_ptr->ooffset == ep_c_ptr->olen+CONTENT_LEN)//写入完毕 短连接关闭
  155.                                         {       
  156.                                                 free(ep_c_ptr);
  157.                                                 if(-1 ==epoll_ctl(epollfd,EPOLL_CTL_DEL,sfd,NULL))
  158.                                                 {
  159.                                                   perror("epoll_ctl err:EPOLL_CTL_DEL");
  160.                                                 }
  161.                                                 close(sfd);
  162.                                                 continue;
  163.                                         }
  164.                                         else //没有写完,继续将文件描述符加入可写事件队列
  165.                                         {
  166.                                                 ev.data.ptr = ep_c_ptr;
  167.                                         ev.events=EPOLLOUT|EPOLLET;
  168.                                         if(-1 == epoll_ctl(epollfd,EPOLL_CTL_MOD,sfd,&ev))
  169.                                         {
  170.                                                 perror("epoll_ctl err:EPOLL_CTL_MOD");
  171.                                                 free(ep_c_ptr);
  172.                                                 close(sfd);
  173.                                                         continue;
  174.                                         }
  175.                                                
  176.                                         }
  177.                                        
  178.                                 }
  179.                                 //继续将文件描述符加入可写事件队列
  180.                                 else if(ret < 0 && errno == EINTR || ret < 0 && errno == EAGAIN || ep_c_ptr->ooffset < ep_c_ptr->olen+CONTENT_LEN)
  181.                                 {
  182.                                         ev.data.ptr = ep_c_ptr;
  183.                                         ev.events=EPOLLOUT|EPOLLET;
  184.                                         if(-1 == epoll_ctl(epollfd,EPOLL_CTL_MOD,sfd,&ev))
  185.                                         {
  186.                                                 perror("epoll_ctl err:EPOLL_CTL_MOD");
  187.                                                 free(ep_c_ptr);
  188.                                                 close(sfd);
  189.                                                         continue;
  190.                                         }
  191.                                 }
  192.                                 else //其它错误的话就关闭端口,释放资源
  193.                                 {
  194.                                         perror("write err");
  195.                                         close(sfd);
  196.                                         free(ep_c_ptr);
  197.                                         continue;
  198.                                 }
  199.                  }
  200.       }
  201.   }
  202.        

  203. }
复制代码

论坛徽章:
6
申猴
日期:2013-10-08 17:32:32金牛座
日期:2013-10-18 19:45:53天秤座
日期:2013-10-18 20:17:34处女座
日期:2014-02-11 10:10:29丑牛
日期:2014-02-15 10:44:15巳蛇
日期:2014-02-18 22:05:54
2 [报告]
发表于 2014-02-14 16:24 |只看该作者
应该是服务器没有关掉与客户端a所创建的套接字,把代码贴出来

论坛徽章:
1
15-16赛季CBA联赛之深圳
日期:2016-02-17 16:12:23
3 [报告]
发表于 2014-02-14 21:28 |只看该作者
回复 2# helpstudy


   
helpstudy 发表于 2014-02-14 16:24
应该是服务器没有关掉与客户端a所创建的套接字,把代码贴出来



关掉了,但是还有CLOSE_WAIT存在,是不是数据滞留在缓冲区,然后下次有请求过来就会把缓冲区的数据当成新客户端发过来的数据?

论坛徽章:
0
4 [报告]
发表于 2014-02-14 22:49 |只看该作者
必然如3楼所说。

论坛徽章:
1
15-16赛季CBA联赛之深圳
日期:2016-02-17 16:12:23
5 [报告]
发表于 2014-02-14 23:15 |只看该作者
本帖最后由 lewy7 于 2014-02-14 23:36 编辑

回复 4# 资深项目经理

感觉自己有变sb的倾向,求解。。
   
诶~出现这种情况的话,服务端就直接堵了,read大部分直接返回0了,但是过了一段时间有稍微有点改善。

论坛徽章:
1
天秤座
日期:2014-04-27 07:42:20
6 [报告]
发表于 2014-02-15 09:33 |只看该作者
新客户端启动没有初始化socke吗?

论坛徽章:
1
15-16赛季CBA联赛之深圳
日期:2016-02-17 16:12:23
7 [报告]
发表于 2014-02-15 12:41 |只看该作者
回复 6# A.com


    即使在另外的客户端,不同的电脑上也是这样

主要问题我觉得还是在这里,这些close_wait总是不消失,只要服务端进程还在。
netstat -anp |grep CLOSE_W
tcp     1712      0 192.168.0.99:4099       192.168.0.99:60471      CLOSE_WAIT  -
tcp     1712      0 192.168.0.99:4099       192.168.0.99:60472      CLOSE_WAIT  -
tcp     1712      0 192.168.0.99:4099       192.168.0.99:60474      CLOSE_WAIT  -
tcp     1712      0 192.168.0.99:4099       192.168.0.99:60476      CLOSE_WAIT  -
tcp     1712      0 192.168.0.99:4099       192.168.0.99:60475      CLOSE_WAIT  -
tcp        1      0 192.168.0.99:4099       192.168.0.99:60473      CLOSE_WAIT  -

论坛徽章:
1
天秤座
日期:2014-04-27 07:42:20
8 [报告]
发表于 2014-02-15 13:28 |只看该作者
客户端的通讯端口都不一样,用的自然不可能是同一个socket。怎么可能在不同电脑上出现这种现象呢?

论坛徽章:
59
2015年亚洲杯之约旦
日期:2015-01-27 21:27:392015年亚洲杯之日本
日期:2015-02-06 22:09:41拜羊年徽章
日期:2015-03-03 16:15:432015年辞旧岁徽章
日期:2015-03-03 16:54:152015年迎新春徽章
日期:2015-03-04 09:50:282015元宵节徽章
日期:2015-03-06 15:50:392015年亚洲杯之阿联酋
日期:2015-03-19 17:39:302015年亚洲杯之中国
日期:2015-03-23 18:52:23巳蛇
日期:2014-12-14 22:44:03双子座
日期:2014-12-10 21:39:16处女座
日期:2014-12-02 08:03:17天蝎座
日期:2014-07-21 19:08:47
9 [报告]
发表于 2014-02-15 13:39 |只看该作者
非Block的噬,
你接收的Timming不对噬,
你要等数据准备好了再收噬~~
你一close,
没准备好的数据(余下的数据)就刷新到用户缓冲区了噬~
所以你每次收到的都是上次的数据噬~

论坛徽章:
1
15-16赛季CBA联赛之深圳
日期:2016-02-17 16:12:23
10 [报告]
发表于 2014-02-15 14:23 |只看该作者
本帖最后由 lewy7 于 2014-02-15 14:30 编辑

回复 8# A.com


    这我也有点懵,因为正常结束或者发生异常后我会close(client_fd),然后下次新的客户端连进来的时候,accept返回的client_fd依然和上个客户端一样

比如上个accept客户端的client_fd=6.关闭后再accpet新的客户端,accpet返回的还是6. ps。如果不关闭的,新的accept返回就是7或者其他非6的整数


感觉自己又向深井冰迈进了一步。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP