免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12下一页
最近访问板块 发新帖
查看: 12729 | 回复: 14

[网络] 网络发送TCP包有很多重传包,是怎么回事? [复制链接]

论坛徽章:
3
2015年迎新春徽章
日期:2015-03-04 09:48:31平安夜徽章
日期:2015-12-26 00:06:30C
日期:2016-10-25 16:26:25
发表于 2012-11-21 18:12 |显示全部楼层
写了两个网络程序,一个客户端,一个服务器端,客户端连过去发送数据包发现对方没接收,通过wireshark抓包发现中间有很多重传包,如图:

网络重传包

网络重传包


大家看下问题出在哪里,谢谢!

论坛徽章:
0
发表于 2012-11-22 10:07 |显示全部楼层
我最近也要做TCP的文件发送。
不知LZ可否分享下主要代码研究下。
个人觉得,socket的东西,大家都会写也没什么难度,基本功能也都能实现
主要的点是程序的健壮性和对复杂网络环境的处理。
感觉自己的程序还有很多需要改进的地方。

论坛徽章:
0
发表于 2012-11-22 19:28 |显示全部楼层
上代码吧,另外,既然你用wireshark抓的包,为何要把时间那列给省了,最好是全图

论坛徽章:
0
发表于 2012-11-22 22:43 |显示全部楼层
理论上,TCP连接立后,应该可以直接发送数据了,但是为什么第4条,192.168.20.120会再次给192.168.50.157发送一次syn+ack呢?另外楼主着得看下第五条,看下,是不是checksum错误还是什么原因?

论坛徽章:
0
发表于 2012-11-22 22:48 |显示全部楼层
感觉三次握手的最后一个包对端没有收到,一直再重发SYN+ACK

论坛徽章:
3
2015年迎新春徽章
日期:2015-03-04 09:48:31平安夜徽章
日期:2015-12-26 00:06:30C
日期:2016-10-25 16:26:25
发表于 2012-11-26 18:07 |显示全部楼层
回复 4# 耗资喜欢猫

大家帮分析下,主体代码如下:

  1. void *network_proc_thread(void *arg)
  2. {
  3.     int listenfd, connfd, sockfd, epfd, nfds, i;
  4.         struct sockaddr_in addr, clientaddr;
  5.     socklen_t clilen = sizeof(struct sockaddr);

  6.         if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
  7.                 log_it("sock create failed!: %s\n", strerror(errno));
  8.                 pthread_exit(-1);
  9.         }

  10.     int listen_port = LISTEN_PORT;

  11.         bzero(&addr, sizeof(addr));
  12.         addr.sin_family = AF_INET;
  13.         addr.sin_port = htons(listen_port);
  14.         addr.sin_addr.s_addr = htonl(INADDR_ANY);

  15.         //重用端口
  16.         int opt = 1;
  17.         if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt))) {
  18.         log_it("setsockopt REUSEADDR error: %s\n", strerror(errno));
  19.     }
  20.         if (bind(listenfd, (struct sockaddr*)&addr, sizeof(addr))) {
  21.                 log_it("sock bind Failed: %s\n", strerror(errno));
  22.                 pthread_exit(-1);
  23.         }
  24.         if (listen(listenfd, 10)) {
  25.         close(listenfd);
  26.                 log_it("sock listen Failed!\n");
  27.                 pthread_exit(-1);
  28.         }

  29.         log_it("network listening on port: %d ......\n", listen_port);

  30.     //把socket设置为非阻塞方式
  31.     set_nonblock(listenfd);

  32.     //声明epoll_event结构体的变量,ev用于注册事件,数组用于回传要处理的事件
  33.     struct epoll_event ev, events[20];
  34.     //生成用于处理accept的epoll专用的文件描述符
  35.     epfd = epoll_create(256);

  36.     ev.data.fd = listenfd;
  37.     ev.events = EPOLLIN | EPOLLET;
  38.     if (epoll_ctl(epfd, EPOLL_CTL_ADD, listenfd, &ev) == -1) {
  39.         perror("epoll_ctl: listenfd");
  40.         exit(1);
  41.     }

  42.     while (1) {
  43.         nfds = epoll_wait(epfd, events, 20, 500);

  44.         for (i = 0; i < nfds; ++i) {
  45.             if(events[i].data.fd == listenfd) {//如果新监测到一个SOCKET用户连接到了绑定的SOCKET端口,建立新的连接。
  46.                 connfd = accept(listenfd, (struct sockaddr *)&clientaddr, &clilen);
  47.                 if (connfd < 0){
  48.                     log_it("accept error!\n");
  49.                     continue;
  50.                 }

  51.                 int port;
  52.                 char ip_addr[20] = {0};
  53.                 get_ip_port(connfd, ip_addr, &port);
  54.                 log_it("receive a connection from: %s : %d, fd: %d ......\n", ip_addr, port, connfd);

  55.                 ev.events = EPOLLIN | EPOLLET;
  56.                 ev.data.fd = connfd;
  57.                 epoll_ctl(epfd, EPOLL_CTL_ADD, connfd, &ev);
  58.             } else if(events[i].events & EPOLLIN) {
  59.                 if ((sockfd = events[i].data.fd) < 0)
  60.                     continue;

  61.                 request_head_t  pkt_head;
  62.                 int n;

  63.                 if ((n = read(sockfd, &pkt_head, sizeof(pkt_head))) < 0) {
  64.                     if (errno == ECONNRESET) {
  65.                         log_it("peer may crash!!\n");
  66.                         close(sockfd);
  67.                         epoll_ctl(epfd, EPOLL_CTL_DEL, sockfd, NULL);
  68.                         continue;
  69.                     } else
  70.                         log_it("read request_head_t error: %d\n", errno);
  71.                 } else if (n == 0) {
  72.                     log_it("peer may close the socket!\n");
  73.                     close(sockfd);
  74.                     epoll_ctl(epfd, EPOLL_CTL_DEL, sockfd, NULL);
  75.                     continue;
  76.                 }
  77.                                
  78.                                 ......  //处理请求
  79.                                
  80.                 ev.data.fd = sockfd;
  81.                 ev.events = EPOLLOUT | EPOLLET;
  82.                 epoll_ctl(epfd, EPOLL_CTL_MOD, sockfd, &ev);

  83.             } else if(events[i].events & EPOLLOUT) {
  84.                 sockfd = events[i].data.fd;

  85.                 ev.data.fd = sockfd;
  86.                 ev.events = EPOLLIN | EPOLLET;
  87.                 epoll_ctl(epfd, EPOLL_CTL_MOD, sockfd, &ev);
  88.             } else if (events[i].events & EPOLLERR) {
  89.                 log_it("fd: %d is bad!\n", events[i].data.fd);
  90.                 close(events[i].data.fd);
  91.                 epoll_ctl(epfd, EPOLL_CTL_DEL, events[i].data.fd, NULL);
  92.             } else if (events[i].events & EPOLLHUP) {
  93.                 log_it("fd : %d EPOLLHUP!\n", events[i].data.fd);
  94.             }
  95.         }
  96.     }

  97.     log_it("network thread exit normally!\n");
  98.     return 0;
  99. }
复制代码
带有时间的抓包截图:

重传包

重传包

论坛徽章:
3
2015年迎新春徽章
日期:2015-03-04 09:48:31平安夜徽章
日期:2015-12-26 00:06:30C
日期:2016-10-25 16:26:25
发表于 2012-11-26 18:10 |显示全部楼层
dolphin836 发表于 2012-11-22 10:07
我最近也要做TCP的文件发送。
不知LZ可否分享下主要代码研究下。
个人觉得,socket的东西,大家都会写也没 ...

我做的不是文件传输,而是一个自定义协议通讯的东东,主要代码见楼上。
关于网络开发这一块跟你有同感,做稳定和容错性好确实很需要花功夫,也需要一定的技术沉淀,这也是我的一个目标。

论坛徽章:
3
2015年迎新春徽章
日期:2015-03-04 09:48:31平安夜徽章
日期:2015-12-26 00:06:30C
日期:2016-10-25 16:26:25
发表于 2012-11-26 18:14 |显示全部楼层
耗资喜欢猫 发表于 2012-11-22 22:43
理论上,TCP连接立后,应该可以直接发送数据了,但是为什么第4条,192.168.20.120会再次给192.168.50.157发 ...

checksum这一块我看了,是“validation disabled”的。

另外说一下,这个程序刚开始跑是没问题的,跑了大概18天才出现的,这中间发生了什么我无从知道。大概还是哪种情况没考虑周全。

论坛徽章:
0
发表于 2012-11-30 11:02 |显示全部楼层
tcp协议保证数据收发。。是不是网络不好,导致丢包,然后tcp协议重传。

论坛徽章:
3
2015年迎新春徽章
日期:2015-03-04 09:48:31平安夜徽章
日期:2015-12-26 00:06:30C
日期:2016-10-25 16:26:25
发表于 2012-11-30 12:27 |显示全部楼层
回复 9# zozoiiiiii


    内网环境,也排除了IP、MAC地址冲突可能性,我怀疑是程序哪里没写好。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP