2012-03-15 79 views
0

送2个的TCP数据包是可以发送2个连续的TCP数据包出在这张照片在这里看到:enter image description here如何在C++

我目前没有设置TCP_NODELAY为true,SO_SNDBUF为0。我也呼吁发送在我的程序2x中。这是我得到的结果:

enter image description here

这里的主要问题将是延迟ACK导致在第二截图降低网络性能。

服务器的代码:

DWORD WINAPI ServerHandler(void *lp){ 
    //The port you want the server to listen on 
    int host_port = 1852; 

    //Initialize socket support WINDOWS ONLY! 
    unsigned short wVersionRequested; 
    WSADATA wsaData; 
    int err; 
    wVersionRequested = MAKEWORD(2, 2); 
    err = WSAStartup(wVersionRequested, &wsaData); 
    if (err != 0 || (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2)) 
    { 
     printf("Could not find useable sock dll %d\n",WSAGetLastError()); 
     return 0; 
    } 

    //Initialize sockets and set any options 
    int hsock; 
    BOOL bOptVal = true; 
    int bOptLen = sizeof (BOOL); 
    int iResult = 0; 

    hsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 
    if(hsock == INVALID_SOCKET) 
    { 
     printf("Error initializing socket %d\n",WSAGetLastError()); 
     return 0; 
    } 

    iResult = setsockopt(hsock, SOL_SOCKET, SO_REUSEADDR, (char *) &bOptVal, bOptLen); 
    if (iResult == SOCKET_ERROR) 
     printf("setsockopt for SO_REUSEADDR failed with error: %d\n", WSAGetLastError()); 
    else 
     printf("Set SO_REUSEADDR: ON\n"); 

    iResult = setsockopt(hsock, SOL_SOCKET, SO_KEEPALIVE, (char *) &bOptVal, bOptLen); 
    if (iResult == SOCKET_ERROR) 
     printf("setsockopt for SO_KEEPALIVE failed with error: %d\n", WSAGetLastError()); 
    else 
     printf("Set SO_KEEPALIVE: ON\n"); 

    //Bind and listen 
    struct sockaddr_in my_addr; 

    my_addr.sin_family = AF_INET ; 
    my_addr.sin_port = htons(host_port); 

    memset(&(my_addr.sin_zero), 0, 8); 
    my_addr.sin_addr.s_addr = INADDR_ANY ; 

    if(bind(hsock, (struct sockaddr*)&my_addr, sizeof(my_addr)) == SOCKET_ERROR) 
    { 
     printf("Error binding to socket, make sure nothing else is listening on this port %d\n",WSAGetLastError()); 
     closesocket(hsock); 
     return 0; 
    } 
    if(listen(hsock, MAXCONN) == SOCKET_ERROR) 
    { 
     printf("Error listening %d\n",WSAGetLastError()); 
     closesocket(hsock); 
     return 0; 
    } 

    //Now lets to the server stuff 

    int* csock; 
    sockaddr_in sadr; 
    int addr_size = sizeof(SOCKADDR); 

    printf("waiting for a connection\n"); 

    while(true) 
    {    
     csock = (int*)malloc(sizeof(int)); 
     if((*csock = accept(hsock, (SOCKADDR*)&sadr, &addr_size))!= INVALID_SOCKET) 
     { 
      printf("Received connection from %s, %u @ socket %d\n", inet_ntoa(sadr.sin_addr), sadr.sin_port, *csock); 

      BOOL bOptVal = true;    
      int iResult = setsockopt(*csock, SOL_SOCKET, TCP_NODELAY, (char *) &bOptVal, sizeof(bOptVal)); 
      if (iResult == SOCKET_ERROR) 
       printf("setsockopt for TCP_NODELAY failed with error: %d\n", WSAGetLastError()); 
      else 
       printf("Set TCP_NODELAY: TRUE\n"); 

      int sendBuf = 0; 
      iResult = setsockopt(*csock, SOL_SOCKET, SO_SNDBUF, (char *) &sendBuf, sizeof(sendBuf)); 
      if (iResult == SOCKET_ERROR) 
       printf("setsockopt for SO_SNDBUF failed with error: %d\n", WSAGetLastError()); 
      else 
       printf("Setsockopt for SO_SNDBUF set to 0\n"); 


      CreateThread(0,0,&SocketHandler, (void*)csock , 0,0); 
     } 
     else 
     { 
      printf("Error accepting %d\n",WSAGetLastError()); 
     } 
    } 
    WSACleanup(); 
} 

我用于发送数据的代码:

int send_TCP_2(int cs, char responseLength[], char data[], int respond_length, int data_length) 
{ 
    int size = respond_length + data_length; 
    int index = 0; 

    // combined 10 byte response with data as 1 packet 
    std::vector<char> packet(size); 

    for(int i=0; i<respond_length; i++) 
    { 
     packet[index] = responseLength[i]; 
     index++; 
    } 

    for(int i=0; i<data_length; i++) 
    { 
     packet[index] = data[i]; 
     index++; 
    } 

    int status; 
    char *data_ptr = &packet[0]; 
    while(size > 0) 
    { 
     status = send(cs, data_ptr, size, 0); 
     if(status > 0) 
     { 
      data_ptr += status; 
      size -= status; 
     } 
     else if (status == SOCKET_ERROR) 
     { 
      int error_code = WSAGetLastError(); 
      printf("send_TCP_2 failed with error code: %d\n", error_code); 
      return 0; // send failed 
     } 
    } 
    return 1; // send successful 
} 

enter image description here

我附上截图时,我不禁内格尔和不触摸SO_SNDBUF。

+1

是什么让你觉得包(而不是别的东西)的大小是影响网络性能?来自同一对网络中同一台计算机的两张屏幕截图吗? – 2012-03-15 03:05:41

+2

'TCP_NODELAY'应该够用了。 – 2012-03-15 03:10:20

+0

@AdamLiss哦不,我并不是说数据包的大小正在影响网络。我试图连续获取2个数据包以获得即时ACK。这将消除第二张照片中看到的200毫秒延迟。 (0.011至0.210) – user990639 2012-03-15 03:17:27

回答

0

感谢所有的建议!将TCP_NODELAY设置为true将会像大多数人所说的那样工作。我在setsockopt中犯了一个愚蠢的错误!

我应该把IPPROTO_TCP,而不是SOL_SOCKET

3

这里的主要问题将是延迟确认,导致第二个屏幕截图中的网络性能变慢。

不,它不会。你错了。您无法控制TCP分组化,或者更确切地说是细分,而您并不需要它。 TCP是一个经过30多年开发的高度优化的流传输协议。

+0

+1,000您正在尝试修复未损坏的内容。充其量,你不会打破它。 (但是,更有可能的是,你*将*通过强制小写来打破它。) – 2012-03-15 08:19:02

+0

EJP非常非常正确...... – Malkocoglu 2012-03-15 08:52:15

+0

TCP并不完美。 TCP是我们的锤子,所以我们将钉子固定在墙上。对于请求/响应通信,TCP有明显的缺点,特别是在窗口方面。关于TCP窗口方案的缺点以及现代HTTP打开一堆TCP连接的趋势,网络上有很多讨论。 – 2012-05-18 18:56:44

0

TCP_NODELAY option set to TRUE应该修复delayed_ACK问题。我曾经发送过两次网络数据包,但是我在ETHERNET (driver) layer中这样做了,它在那里工作(delayed_ACK是由另一方引起的),但是在这一层(SOCKET层)你不能做这样的事情。另外,不要将SO_SNDBUF设置为0 ...