请问为何tcp send第一次时很慢, 第二次时很快呢?(附代码和测试结果)

testtcpsend 发布于 2016/08/30 12:11
阅读 1K+
收藏 1



#include<sys/types.h>
 #include<sys/socket.h>
 #include<netinet/in.h>
 #include<arpa/inet.h>
 #include<unistd.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <strings.h>
 #include<sys/wait.h>
 #include <string.h>
#include <time.h> 
#include <unistd.h>
 #include <fcntl.h>
#include <sys/time.h>
#include <stdio.h>
#include  <netinet/in.h>
 #include <netinet/tcp.h> // for TCP_NODELAY
#include <sys/time.h>
#include <sys/epoll.h>
#include <time.h>


typedef unsigned int            uint32_t; 
 void xsleep(uint32_t ms)
 { 
   struct timeval tval;
   tval.tv_sec = ms / 1000;
   tval.tv_usec = ( ms * 1000) % 1000000;
   select(0, NULL, NULL, NULL, &tval);
 } 



 int main(int argc, char ** argv) 
 { 
     int sockfd,new_fd;
     struct sockaddr_in my_addr;
     struct sockaddr_in their_addr;
     unsigned int sin_size, myport, lisnum; 
  
     if(argv[1])  myport = atoi(argv[1]); 
     else myport = 50000; 
  
     if(argv[2])  lisnum = atoi(argv[2]); 
     else lisnum = 2; 
  
     if ((sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1) { 
         perror("socket"); 
         exit(1); 
     } 
  printf("socket %d ok \n",myport);
//fcntl(sockfd, F_SETFL, O_NONBLOCK);
    my_addr.sin_family=PF_INET; 
     my_addr.sin_port=htons(myport); 
     my_addr.sin_addr.s_addr = INADDR_ANY; 
     bzero(&(my_addr.sin_zero), 0); 
     if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) == -1) { 
         perror("bind"); 
         exit(1); 
     } 
  printf("bind ok \n");
  
     if (listen(sockfd, lisnum) == -1) { 
         perror("listen"); 
         exit(1); 
     }
  printf("listen ok \n");
 



    sin_size = sizeof(struct sockaddr_in);


xxx:
     if ((new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size)) == -1) { 
         perror("accept"); 
   goto xxx;
     }






     printf("server: got connection from %s\n",inet_ntoa(their_addr.sin_addr));
fcntl(new_fd, F_SETFL, O_NONBLOCK);
int arg = 1;
setsockopt(new_fd, IPPROTO_TCP, TCP_NODELAY, (char*)&arg, sizeof(int));
int nSendBuf=1024*1024*16;//¨¦??32K
setsockopt(new_fd,SOL_SOCKET,SO_SNDBUF,(const char*)&nSendBuf,sizeof(int));



int epfd;
struct epoll_event ev,events[20];
epfd=epoll_create(256);


ev.data.fd=sockfd;
ev.events=EPOLLIN|EPOLLOUT;
epoll_ctl(epfd,EPOLL_CTL_ADD,sockfd,&ev);


ev.data.fd=new_fd;
ev.events=EPOLLIN|EPOLLOUT;
epoll_ctl(epfd,EPOLL_CTL_ADD,new_fd,&ev);






 int   step = 0;
   char  szSnd[1024] = {0};
   memset(szSnd,97,1024);
szSnd[100] = 0;


//time_t lasttime = time(NULL);
struct timeval lasttime;
gettimeofday(&lasttime,0);
double alltimeuse = 0.0;



int iii = 0;
while(iii++<100)
{
struct timeval lasttime;
gettimeofday(&lasttime,0);


 if (send(new_fd, szSnd, strlen(szSnd), 0) == -1) {
     perror("send");
 }



struct timeval now_time;
gettimeofday(&now_time,0);
double timeuse = 1000000.0*(now_time.tv_sec - lasttime.tv_sec) + now_time.tv_usec - lasttime.tv_usec;
timeuse /=1000.0;
 printf("xxsend msg: %f\n",(timeuse));






{
struct timeval lasttime;
gettimeofday(&lasttime,0);


 if (send(new_fd, szSnd, strlen(szSnd), 0) == -1) {
     perror("send");
 }



struct timeval now_time;
gettimeofday(&now_time,0);
double timeuse = 1000000.0*(now_time.tv_sec - lasttime.tv_sec) + now_time.tv_usec - lasttime.tv_usec;
timeuse /=1000.0;
 printf("xxsend1 msg: %f\n",(timeuse));
}


for(int ccc=0; ccc<1000000; ccc++)
   {
char aaax[10240];
memset(aaax,0,10240);
}
//xsleep(100);
//usleep(1000);
};


 exit(0); 
 }




测试结果: send很慢, send1很快
socket 50000 ok 
bind ok 
listen ok 
server: got connection from 192.168.125.69
xxsend msg: 0.327000
xxsend1 msg: 0.126000
xxsend msg: 0.058000
xxsend1 msg: 0.041000
xxsend msg: 0.028000
xxsend1 msg: 0.002000
xxsend msg: 0.929000
xxsend1 msg: 0.002000
xxsend msg: 0.045000
xxsend1 msg: 0.002000
xxsend msg: 0.068000
xxsend1 msg: 0.045000
xxsend msg: 0.054000
xxsend1 msg: 0.001000
xxsend msg: 0.044000
xxsend1 msg: 0.040000
xxsend msg: 0.029000
xxsend1 msg: 0.023000
xxsend msg: 3.455000
xxsend1 msg: 0.002000
xxsend msg: 0.050000
xxsend1 msg: 0.028000
xxsend msg: 0.061000
xxsend1 msg: 0.002000
xxsend msg: 0.049000
xxsend1 msg: 0.036000
xxsend msg: 0.179000
xxsend1 msg: 0.035000
xxsend msg: 0.048000
xxsend1 msg: 0.001000
xxsend msg: 0.058000
xxsend1 msg: 0.012000
xxsend msg: 0.053000
xxsend1 msg: 0.001000
xxsend msg: 0.065000
xxsend1 msg: 0.001000
xxsend msg: 0.030000
xxsend1 msg: 0.011000
xxsend msg: 0.151000
xxsend1 msg: 0.002000
xxsend msg: 0.059000
xxsend1 msg: 0.003000
xxsend msg: 0.054000
xxsend1 msg: 0.001000
xxsend msg: 0.053000
xxsend1 msg: 0.002000
xxsend msg: 0.047000
xxsend1 msg: 0.002000
xxsend msg: 0.045000
xxsend1 msg: 0.002000
xxsend msg: 0.118000
xxsend1 msg: 0.002000
xxsend msg: 0.143000
xxsend1 msg: 0.002000





加载中
0
t
testtcpsend
测试结果:可见第一次send很慢, 第二次send1很快, 如果while循环一直连续send就超快, 几十万次的确小意思, 但是一旦期间有其他代码执行下一次send就超慢, 在现实业务中肯定send完之后要做其他事情, 为何会这样?
0
t
testtcpsend
高手何在?
0
bnynk
bnynk

会不会和TCP的慢启动机制有关?可参见下文http://www.cnblogs.com/ggjucheng/archive/2012/02/02/2335994.html


0
吃石榴不吐核
吃石榴不吐核
TCP第一次建立连接会有三次握手过程。
0
pj220
pj220

这个问题太复杂有太多的因素:

1、第一次send内核里应该有一大堆的初始化工作,后续的send很多时候并没有真的执行send工作,只是把数据做了缓存(等存够了一定量数据再组成一个底层数据包发送,这样能提高发送效率),并没有实际发送。

2、中间执行了其他的代码有可能发生了线程的切换,线程的切换是需要一定时间的,切换的时间也算在了发送时间里,所以你看到的现象就是发送时间变长。

3、网络路由和协议底层的一些复杂优化机制,导致第一次或者切换回来,发送时间变长。比如楼上的兄弟所说的慢启动机制。

综上所述,你的这个问题比较复杂,不是简单一句话

 

返回顶部
顶部