2013-02-12 44 views
0

當我試圖連接到服務器只有一個客戶端,服務器recv()功能不會延遲。c + + tcp服務器(windows操作系統) - recv()延遲當有多個1連接到服務器

但是,當我啓動客戶端控制檯多於1次(類似7次)時,發送到服務器數據包的功能send()之後會有2000毫秒的延遲,直到服務器將打印數據包在控制檯中。

是否有任何解決方案,無需爲每個客戶端啓動線程? (Windows限制每個進程的線程數量)。

代碼編譯與Visual Studio 2008,這是完整的服務器代碼:

#include <WinSock2.h> 
#include <ws2tcpip.h> 
#pragma comment(lib, "ws2_32.lib") 
#include <Windows.h> 
#include <stdio.h> 

struct sslv3 
{ 
#define max_clients 1024 
private: 
    int cClient; 
public: 
    SOCKET fd; 
    int CurrentClient() 
    { 
     return cClient; 
    } 
    struct client 
    { 
     client() 
     { 
      Valid = false; 
     } 
     bool Valid; 
     DWORD ip; 
     WORD port; 
     char ipstr[33]; 
     char portstr[33]; 
     SOCKET fd; 
     void StrGen() 
     { 
      wsprintf(ipstr, "%d.%d.%d.%d", ip & 0xFF, (ip & 0xFF00)/0x100, (ip & 0xFF0000)/0x10000, (ip & 0xFF000000)/0x1000000); 
      wsprintf(portstr, "%d", port); 
     } 
    } clients[max_clients]; 
    // 
    sslv3(bool server_client) 
    { 
     WSADATA wsaData; 
     WSAStartup(MAKEWORD(2, 2), &wsaData); 
     cClient = 0; 
     fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 
     // 
     DWORD timeout = 1; 
     setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout, sizeof(DWORD)); 
    } 
    int Bind(WORD port) 
    { 
     int ret = 0; 
     sockaddr_in local; 
     local.sin_addr.s_addr = htonl(INADDR_ANY); 
     local.sin_family = AF_INET; 
     local.sin_port = htons(port); 
     if((ret = bind(fd, (struct sockaddr *)&local, sizeof(local))) 
      != SOCKET_ERROR) 
      listen(fd, SOMAXCONN); 
     return ret; 
    } 
    int Accept() 
    { 
     SOCKET clientfd; 
     sockaddr_in client; 
     int addrlen = sizeof(client); 
     clientfd = accept(fd, (struct sockaddr *)&client, &addrlen); 
     if(clientfd == -1) 
      return -1; 
     clients[cClient].ip = client.sin_addr.S_un.S_addr; 
     clients[cClient].port = client.sin_port; 
     clients[cClient].StrGen(); 
     clients[cClient].fd = clientfd; 
     clients[cClient].Valid = true; 
     // 
     DWORD timeout = 1; 
     setsockopt(clients[cClient].fd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout, sizeof(DWORD)); 
     cClient++; 
     if(cClient >= max_clients) 
     { 
      cClient = 0; 
      return max_clients - 1; 
     } 
     return cClient - 1; 
    } 
    int Connect(char ip[], WORD port) 
    { 
     sockaddr_in addr; 
     addr.sin_family = AF_INET; 
     addr.sin_addr.s_addr = inet_addr(ip); 
     addr.sin_port = htons(port); 
     return connect(fd, (const struct sockaddr*)&addr, sizeof(addr)); 
    } 
    int Send(SOCKET sfd, void* buffer, int length) 
    { 
     return send(sfd, (char*)buffer, length, 0); 
    } 
    int Read(SOCKET sfd, void* buffer, int length) 
    { 
     return recv(sfd, (char*)buffer, length, 0); 
    } 
}; 

sslv3 cssl(true); 

DWORD WINAPI ReadThread(void* args) 
{ 
    while(true) 
    { 
     for(int j = 0; j <= cssl.CurrentClient(); j++) 
     { 
      if(cssl.clients[j].Valid) 
      { 
       char rpack[1024]; 
       for(int i = 0; i < sizeof(rpack); i++) 
        rpack[i] = 0; 
       if(cssl.Read(cssl.clients[j].fd, rpack, sizeof(rpack)) > 0){ 
        printf("%s:%s says: %s\n", cssl.clients[j].ipstr, cssl.clients[j].portstr, rpack); 
       } 
      } 
     } 
     Sleep(1); 
    } 
    return TRUE; 
} 

int main() 
{ 
    cssl.Bind(1234); 
    CreateThread(0,0,ReadThread,0,0,0); 
    while(true) 
    { 
     Sleep(1); 
     int cid = cssl.Accept(); 
     if(cid != -1){ 
      printf("%s:%s connected!\n", cssl.clients[cid].ipstr, cssl.clients[cid].portstr); 
     } 
    } 
    return 0; 
} 

下面是一個完整的客戶端代碼:

#include <WinSock2.h> 
#include <ws2tcpip.h> 
#pragma comment(lib, "ws2_32.lib") 
#include <Windows.h> 
#include <stdio.h> 

#include <iostream> 
using namespace std; 

struct sslv3 
{ 
#define max_clients 1024 
private: 
    int cClient; 
public: 
    SOCKET fd; 
    int CurrentClient() 
    { 
     return cClient; 
    } 
    struct client 
    { 
     client() 
     { 
      Valid = false; 
     } 
     bool Valid; 
     DWORD ip; 
     WORD port; 
     char ipstr[33]; 
     char portstr[33]; 
     SOCKET fd; 
     void StrGen() 
     { 
      wsprintf(ipstr, "%d.%d.%d.%d", ip & 0xFF, (ip & 0xFF00)/0x100, (ip & 0xFF0000)/0x10000, (ip & 0xFF000000)/0x1000000); 
      wsprintf(portstr, "%d", port); 
     } 
    } clients[max_clients]; 
    // 
    sslv3(bool server_client) 
    { 
     WSADATA wsaData; 
     WSAStartup(MAKEWORD(2, 2), &wsaData); 
     cClient = 0; 
     fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 
     // 
     DWORD timeout = 1; 
     setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout, sizeof(DWORD)); 
    } 
    int Bind(WORD port) 
    { 
     int ret = 0; 
     sockaddr_in local; 
     local.sin_addr.s_addr = htonl(INADDR_ANY); 
     local.sin_family = AF_INET; 
     local.sin_port = htons(port); 
     if((ret = bind(fd, (struct sockaddr *)&local, sizeof(local))) 
      != SOCKET_ERROR) 
      listen(fd, SOMAXCONN); 
     return ret; 
    } 
    int Accept() 
    { 
     SOCKET clientfd; 
     sockaddr_in client; 
     int addrlen = sizeof(client); 
     clientfd = accept(fd, (struct sockaddr *)&client, &addrlen); 
     if(clientfd == -1) 
      return -1; 
     clients[cClient].ip = client.sin_addr.S_un.S_addr; 
     clients[cClient].port = client.sin_port; 
     clients[cClient].StrGen(); 
     clients[cClient].fd = clientfd; 
     clients[cClient].Valid = true; 
     // 
     DWORD timeout = 1; 
     setsockopt(clients[cClient].fd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout, sizeof(DWORD)); 
     cClient++; 
     if(cClient >= max_clients) 
     { 
      cClient = 0; 
      return max_clients - 1; 
     } 
     return cClient - 1; 
    } 
    int Connect(char ip[], WORD port) 
    { 
     sockaddr_in addr; 
     addr.sin_family = AF_INET; 
     addr.sin_addr.s_addr = inet_addr(ip); 
     addr.sin_port = htons(port); 
     return connect(fd, (const struct sockaddr*)&addr, sizeof(addr)); 
    } 
    int Send(SOCKET sfd, void* buffer, int length) 
    { 
     return send(sfd, (char*)buffer, length, 0); 
    } 
    int Read(SOCKET sfd, void* buffer, int length) 
    { 
     return recv(sfd, (char*)buffer, length, 0); 
    } 
}; 

sslv3 cssl(false); 

int main() 
{ 
    cssl.Connect("127.0.0.1", 1234); 
    while(true) 
    { 
     printf("say: "); 
     char buf[1024]; 
     for(int i = 0; i < sizeof(buf); i++) 
      buf[i] = 0; 
     cin >> buf; 
     int len = strlen(buf); 
     cssl.Send(cssl.fd, buf, len); 
    } 
    return 0; 
} 
+0

你寫了一個無限循環,在其睡眠和你問的延遲? – EJP 2013-02-12 11:49:21

+0

它休眠1ms給CPU一個休息。 – 2013-02-12 12:37:53

+0

它應該調用select()來'給CPU一箇中斷',具有正確的持續時間。 – EJP 2013-02-12 20:27:31

回答

0

的服務器似乎「空閒」了2秒,因爲某些客戶端在2個sleep秒之後處理,每個1秒。

這顯然不是在服務器上處理多個客戶端的正確方法。你可能想檢查select() - reference

一個很好的教程套接字編程是Beej's

+0

謝謝 - 作品:) – 2013-02-12 12:36:38