2016-08-01 120 views
0

這是我目前的代碼,我正在研究引入線程以允許服務器同時處理多個客戶端,但是我在理解如何執行此操作時遇到了一些麻煩。任何幫助,將不勝感激。Winsock - 允許多個客戶端線程

客戶:

int create_client() 
{ 

WSADATA wsaData; 
SOCKET ConnectSocket = INVALID_SOCKET; 
struct addrinfo *result = NULL, 
       *ptr = NULL, 
       hints; 

char *sendbuf = "this is a test"; 
char recvbuf[DEFAULT_BUFLEN]; 
int iResult; 
int recvbuflen = DEFAULT_BUFLEN; 

// Initialize Winsock 
iResult = WSAStartup(MAKEWORD(2,2), &wsaData); 
if (iResult != 0) { 
    printf("WSAStartup failed with error: %d\n", iResult); 
    return 1; 
} 

ZeroMemory(&hints, sizeof(hints)); 
hints.ai_family = AF_UNSPEC; 
hints.ai_socktype = SOCK_STREAM; 
hints.ai_protocol = IPPROTO_TCP; 

// Resolve the server address and port 
iResult = getaddrinfo(DEFAULT_IP, DEFAULT_PORT, &hints, &result); 
if (iResult != 0) { 
    printf("getaddrinfo failed with error: %d\n", iResult); 
    WSACleanup(); 
    return 1; 
} 

// Attempt to connect to an address until one succeeds 
for(ptr=result; ptr != NULL ;ptr=ptr->ai_next) { 

    // Create a SOCKET for connecting to server 
    ConnectSocket = socket(ptr->ai_family, ptr->ai_socktype, 
     ptr->ai_protocol); 
    if (ConnectSocket == INVALID_SOCKET) { 
     printf("socket failed with error: %ld\n", WSAGetLastError()); 
     WSACleanup(); 
     return 1; 
    } 

    // Connect to server. 
    iResult = connect(ConnectSocket, ptr->ai_addr, (int)ptr->ai_addrlen); 
    if (iResult == SOCKET_ERROR) { 
     closesocket(ConnectSocket); 
     ConnectSocket = INVALID_SOCKET; 
     continue; 
    } 
    break; 
} 

freeaddrinfo(result); 

if (ConnectSocket == INVALID_SOCKET) { 
    printf("Unable to connect to server!\n"); 
    WSACleanup(); 
    return 1; 
} 

// Send an initial buffer 
iResult = send(ConnectSocket, sendbuf, (int)strlen(sendbuf), 0); 
if (iResult == SOCKET_ERROR) { 
    printf("send failed with error: %d\n", WSAGetLastError()); 
    closesocket(ConnectSocket); 
    WSACleanup(); 
    return 1; 
} 

printf("Bytes Sent: %ld\n", iResult); 

// shutdown the connection since no more data will be sent 
iResult = shutdown(ConnectSocket, SD_SEND); 
if (iResult == SOCKET_ERROR) { 
    printf("shutdown failed with error: %d\n", WSAGetLastError()); 
    closesocket(ConnectSocket); 
    WSACleanup(); 
    return 1; 
} 

// Receive until the peer closes the connection 
do { 

    iResult = recv(ConnectSocket, recvbuf, recvbuflen, 0); 
    if (iResult > 0) 
     printf("Bytes received: %d\n", iResult); 
    else if (iResult == 0) 
     printf("Connection closed\n"); 
    else 
     printf("recv failed with error: %d\n", WSAGetLastError()); 

} while(iResult > 0); 

// cleanup 
closesocket(ConnectSocket); 
WSACleanup(); 

return 0; 
} 

服務器:

WSADATA wsaData; 
int iResult; 

SOCKET ListenSocket = INVALID_SOCKET; 
SOCKET ClientSocket = INVALID_SOCKET; 

struct addrinfo *result = NULL; 
struct addrinfo hints; 

int iSendResult; 
char recvbuf[DEFAULT_BUFLEN]; 
int recvbuflen = DEFAULT_BUFLEN; 

// Initialize Winsock 
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData); 
if (iResult != 0) { 
    printf("WSAStartup failed with error: %d\n", iResult); 
    return 1; 
} 

ZeroMemory(&hints, sizeof(hints)); 
hints.ai_family = AF_INET; 
hints.ai_socktype = SOCK_STREAM; 
hints.ai_protocol = IPPROTO_TCP; 
hints.ai_flags = AI_PASSIVE; 

// Resolve the server address and port 
iResult = getaddrinfo(NULL, DEFAULT_PORT, &hints, &result); 
if (iResult != 0) { 
    printf("getaddrinfo failed with error: %d\n", iResult); 
    WSACleanup(); 
    return 1; 
} 

// Create a SOCKET for connecting to server 
ListenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol); 
if (ListenSocket == INVALID_SOCKET) { 
    printf("socket failed with error: %ld\n", WSAGetLastError()); 
    freeaddrinfo(result); 
    WSACleanup(); 
    return 1; 
} 

// Setup the TCP listening socket 
iResult = bind(ListenSocket, result->ai_addr, (int)result->ai_addrlen); 
if (iResult == SOCKET_ERROR) { 
    printf("bind failed with error: %d\n", WSAGetLastError()); 
    freeaddrinfo(result); 
    closesocket(ListenSocket); 
    WSACleanup(); 
    return 1; 
} 

freeaddrinfo(result); 

iResult = listen(ListenSocket, SOMAXCONN); 
if (iResult == SOCKET_ERROR) { 
    printf("listen failed with error: %d\n", WSAGetLastError()); 
    closesocket(ListenSocket); 
    WSACleanup(); 
    return 1; 
} 

cout << "Server initalized." << endl; 

// Accept a client socket 
ClientSocket = accept(ListenSocket, NULL, NULL); 
if (ClientSocket == INVALID_SOCKET) { 
    printf("accept failed with error: %d\n", WSAGetLastError()); 
    closesocket(ListenSocket); 
    WSACleanup(); 
    return 1; 
} 

// No longer need server socket 
closesocket(ListenSocket); 

// Receive until the peer shuts down the connection 
do { 

    iResult = recv(ClientSocket, recvbuf, recvbuflen, 0); 
    if (iResult > 0) { 
     printf("Bytes received: %d\n", iResult); 

     // Echo the buffer back to the sender 
     iSendResult = send(ClientSocket, recvbuf, iResult, 0); 
     if (iSendResult == SOCKET_ERROR) { 
      printf("send failed with error: %d\n", WSAGetLastError()); 
      closesocket(ClientSocket); 
      WSACleanup(); 
      return 1; 
     } 
     printf("Bytes sent: %d\n", iSendResult); 
    } else if (iResult == 0) 
     printf("Connection closing...\n"); 
    else { 
     printf("recv failed with error: %d\n", WSAGetLastError()); 
     closesocket(ClientSocket); 
     WSACleanup(); 
     return 1; 
    } 

} while (iResult > 0); 

// shutdown the connection since we're done 
iResult = shutdown(ClientSocket, SD_SEND); 
if (iResult == SOCKET_ERROR) { 
    printf("shutdown failed with error: %d\n", WSAGetLastError()); 
    closesocket(ClientSocket); 
    WSACleanup(); 
    return 1; 
} 

// cleanup 
closesocket(ClientSocket); 
WSACleanup(); 

return 0; 
} 
+0

任何錯誤信息? – Takarii

回答

0

你應該分開聆聽和加工零件。

所以,你的主線程會監聽套接字,並且當接收到一些連接時創建一個threa。

線程將接受連接有客戶端套接字,讀取和進程。

僞代碼爲您主線:

while (true){ 
    listen the socket 
    if any entry connection{ 
     create thread and process the petition 
    } 
} 

僞代碼對你的線程:

accept connection and obtain the client socket 
process it 
close the client socket 

編輯: PD:這只是一個暫時的解決方案,在任何實際生活狀況巨大的請願將無法正常工作。

+0

謝謝,我得到它的工作!在現實生活中,會做什麼呢?我假設你的意思是有這麼多的線程處理x客戶端將不會有效。 – Taliyah

+0

我沒有任何使用有效方法的真實體驗,但我認爲這可以幫助您對此有一個想法,http://vichargrave.com/multithreaded-work-queue-based-server-2/ 另一個想法可以有一個「游泳池」的請願書,然後使用有效的方法來平衡可分辨的線程使用,將「作品」從池中傳遞到線索並收集結果。 – Raskayu