2013-09-26 53 views
1

当我执行连续发送时,以及在客户端上接收到recv后,我遇到了与通过套接字进行的客户端/服务器通信有关的问题。例如:客户端/服务器之间的C++/Winsock TCP发送/ recv问题

方案A:

Client    Server 
send(...);----------->While(recv(...)>0){ 
send(...);-----------> print(message); 
send(...);----------->} 
recv(...);----------->Send(...); 

服务器接收3个消息,并发送最后的答案,但对客户端的recv失败SOCKET_ERROR与WSAGetLastError()的10060 的唯一途径值,使这种情况下工作是当我在客户端上次发送后添加关闭(...,SD_SEND)时。

为什么案例A有这种行为?以及为什么它只在添加shutdown()命令时才起作用?

但是,如果我做的:

案例B:

Client    Server 
send(...);----------->While(recv(...)>0){ 
recv(...);-----------> send(...); 
send(...);-----------> ... 
recv(...);-----------> ... 
send(...);-----------> ... 
recv(...);----------->} 

它正常工作,服务器/客户端接收和发送的每条消息。

这里是代码的情况下答: 客户:

#include <iostream> 
#include <winsock2.h> 
#include <ws2tcpip.h> 
#include <stdlib.h> 
#include <stdio.h> 
#include <string.h> 

// Need to link with Ws2_32.lib, Mswsock.lib, and Advapi32.lib 
#pragma comment (lib, "Ws2_32.lib") 
#pragma comment (lib, "Mswsock.lib") 
#pragma comment (lib, "AdvApi32.lib") 

#define DEFAULT_BUFLEN 1024 
#define DEFAULT_PORT "27015" 

int main() { 
WSADATA wsaData; 
SOCKET ConnectSocket = INVALID_SOCKET; 
ADDRINFOA *ptr = NULL, *result = NULL, hints; 
char *ans, *sendbuf = "message\0"; 
char recvbuf[1024]; 
int iResult; 
int recvbuflen = DEFAULT_BUFLEN; 
ans=new char[1024]; 

// Initialize Winsock 
iResult = WSAStartup(MAKEWORD(2,2), &wsaData); 
printf("--> Initializing Winsock...\n*** Version: %s\n", wsaData.szDescription); 
if (iResult != 0) { 
    printf("*** Could not initialize Socket.\n*** Error code: %d", 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("127.0.0.1", DEFAULT_PORT, &hints, &result); 
printf("--> Setting server address...\n"); 
printf("--> local ip: 127.0.0.1 at port: %s...\n",DEFAULT_PORT); 
if (iResult != 0) { 
    printf("*** Error in setting server address.\n*** Error code: %d", 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 
    printf("--> Creating client socket object...\n"); 
    ConnectSocket = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol); 
    if (ConnectSocket == INVALID_SOCKET) { 
     printf("*** Error creating socket.\n*** Error code: %d\n",WSAGetLastError()); 
     freeaddrinfo(result); 
     WSACleanup(); 
     return 1; 
    } 
    if(setsockopt(ConnectSocket, SOL_SOCKET, SO_RCVTIMEO, (char *)new int(1000), sizeof(int))){ 
     WSACleanup(); 
     //strcpy(recvbuf, "EX_95"); 
     return -5; // Error setting recv timeout. 
    } 
    // Connect to server. 
    iResult = connect(ConnectSocket, ptr->ai_addr, (int)ptr->ai_addrlen); 
    if (iResult == SOCKET_ERROR) { 
     closesocket(ConnectSocket); 
     ConnectSocket = INVALID_SOCKET; 
     continue; 
    } 
    printf("*** Client ready *** \n\n"); 
    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: %d\n", WSAGetLastError()); 
    closesocket(ConnectSocket); 
    WSACleanup(); 
    return 1; 
} 

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

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

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


iResult = send(ConnectSocket, sendbuf, (int)strlen(sendbuf), 0); 
if (iResult == SOCKET_ERROR) { 
    printf("*** Send failed: %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; 
}*/ 

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()); 


// cleanup 
closesocket(ConnectSocket); 
WSACleanup(); 
system("pause"); 
return 0; 
} 

服务器:

// Need to link with Ws2_32.lib, Mswsock.lib, and Advapi32.lib 
#include <iostream> 
#include <Winsock2.h> 
#include <Ws2tcpip.h> 
#include <string> 

#pragma comment (lib, "Ws2_32.lib") 
#pragma comment (lib, "Mswsock.lib") 
#pragma comment (lib, "AdvApi32.lib") 

const char* DEFAULT_PORT = "27015"; 
const int DEFAULT_BUFLEN = 1024; 

using namespace std; 

int main(){ 
//Connection Variables. 
WSADATA wsaData; 
ADDRINFOA *result = NULL, hints; 
SOCKADDR *clientInfo = NULL; 
int iResult; 
//Receive Variables. 
char recvBuff[DEFAULT_BUFLEN]; 
int recvBuffLen = DEFAULT_BUFLEN; 
int iSendResult; 
//Server/Client sockets. 
SOCKET ListenSocket = INVALID_SOCKET; //SOCKET for the server to listen for client connections. 
SOCKET ClientSocket = INVALID_SOCKET; 

//Initialize Winsock 
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData); 
printf("--> Initializing Winsock...\n*** Version: %s\n", wsaData.szDescription); 
if (iResult != 0){ 
    printf("*** Could not initialize Socket.\n*** Error code: %d", iResult); 
    return 1; 
} 
//Initialize hints allocated memory. 
ZeroMemory(&hints, sizeof(hints)); 

hints.ai_family = AF_INET;  //AF_INET is used to specify the IPv4 address family. 
hints.ai_socktype = SOCK_STREAM; //SOCK_STREAM is used to specify a stream socket. 
hints.ai_protocol = IPPROTO_TCP; //IPPROTO_TCP is used to specify the TCP protocol. 
hints.ai_flags = AI_PASSIVE; //AI_PASSIVE The socket address will be used in a call to the bind function. 

printf("--> Getting address info from server...\n"); 
iResult = getaddrinfo(NULL, DEFAULT_PORT, &hints, &result); 
if(iResult != 0){ 
    printf("*** Error in getting address info from server.\n*** Error code: %d", iResult); 
    WSACleanup(); 
    return 2; 
} 

printf("--> Creating server socket object...\n"); 
//printf("Create socket to ip: %s at port: %s\n", inet_ntoa(((SOCKADDR_IN*)(result->ai_addr))->sin_addr),DEFAULT_PORT); 
ListenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol); 
if(ListenSocket == INVALID_SOCKET){ 
    printf("*** Error creating socket.\n*** Error code: %d\n",WSAGetLastError()); 
    freeaddrinfo(result); 
    WSACleanup(); 
    return 3; 
} 

//BIND()->Associates a local address to a socket. 
printf("--> Bind listen object to local ip: 127.0.0.1 at port: %s...\n",DEFAULT_PORT); 
iResult = bind(ListenSocket, result->ai_addr, result->ai_addrlen); 
if(iResult == SOCKET_ERROR){ 
    printf("*** Binding failed.\n*** Error code: %d\n", WSAGetLastError()); 
    closesocket(ListenSocket); 
    freeaddrinfo(result); 
    WSACleanup(); 
    return 4; 
} 
freeaddrinfo(result); 

printf("*** Server ONLINE: Listening...\n\n"); 
iResult = listen(ListenSocket, SOMAXCONN); 
if(iResult == SOCKET_ERROR){ 
    printf("*** Failed start listening.\n*** Error code: %d\n",WSAGetLastError()); 
    closesocket(ListenSocket); 
    freeaddrinfo(result); 
    WSACleanup(); 
    return 5; 
} 

for(;1;){ 
    ClientSocket = accept(ListenSocket,clientInfo, NULL); 
    if(ClientSocket == INVALID_SOCKET){ 
     printf("*** Failed accepting connection from client.\n*** Error code: %d\n",WSAGetLastError()); 
     continue; 
    } 
    else{ 
     printf("--> Connection accepted from client.\n"); 
     iResult=1; 
     while(iResult > 0){ 
      iResult = recv(ClientSocket, recvBuff, recvBuffLen, 0); 
      if(iResult > 0){ 
       printf("--> Message received: %s\n--> Total: %d\n", recvBuff, iResult); 
      } 
     } 
     iSendResult = send(ClientSocket, "Answer\0", DEFAULT_BUFLEN, 0); 
     if(iSendResult == SOCKET_ERROR){ 
      printf("*** Sending data failed.\n*** Error code: %d\n",WSAGetLastError()); 
      continue; 
     } 
     else{ 
      printf("--> Sent: %d bytes\n", iSendResult); 
     } 
     printf("*** Closing connection... \n\n"); 
     iResult = shutdown(ClientSocket, SD_BOTH); 
     if(iResult == SOCKET_ERROR){ 
      printf("*** Shutdown client failed.\nError code: %d\n",WSAGetLastError()); 
      closesocket(ClientSocket); 
      WSACleanup(); 
      return 9; 
     } 
    } 
} 
closesocket(ClientSocket); 
WSACleanup(); 
system("pause"); 
return 0; 
} 

在此先感谢!!!! Nicolas Miranda S.

+1

当你得到SOCKET_ERROR时,什么是valueOf WSAGetLastError()? – EJP

+0

嗨EJP,谢谢你的回答。 WSAGetLastError()的值是10060 –

回答

1

当客户端等待响应并因此无法发送任何内容时,服务器在recv调用中被阻塞。您的接收器超时为1秒,因此1秒后客户端会生成超时错误(WSAETIMEDOUT == 10060)。

当您执行关机时,只能指定SD_SEND,因此连接未关闭,但会导致服务器退出recv,因此它可以发送响应。

注意:recv将阻塞,直到收到流套接字(SOCK_STREAM)的内容。您应该查看select()函数,以了解如何在调用recv之前“查看”是否有可用的数据。

下面是使用选择的一个示例:

fd_set fds; 
    timeval tv; 
    tv.tv_sec = 5000; 
    fds.fd_count = 1; 
    fds.fd_array[0] = ClientSocket; 

    int select_result = select(1, &fds, NULL, NULL, &tv); 

如果select_result == 0,有一个超时。否则,fd_set中的一个套接字已准备好数据。这里只有一个,它在select调用中被指定为readfds。

您需要重新安排应用程序,以便您有一些导致服务器发送响应的事件(例如,接收到第三条消息,或某些超时没有收到任何消息,或消息本身有某些事件)。您可以使用第二个线索进行回复,但这超出了我可以在简短回答中显示的内容。

+0

非常感谢! 现在它正在处理你的方法= D –

相关问题