Socket编程C / C ++ – recv函数在服务器中挂起

我在使用recv函数时遇到问题

我有一个从客户端发送一些数据的应用程序,这些数据由服务器接收并根据数据发送响应。

当我发送less于16个请求时,实现工作正常。 但是,当我从客户端发送超过16个请求(一个接一个)时,从服务器到第16个请求的响应都没有问题,但在此之后服务器挂起。 我可以看到数据是从客户端传输,但没有被服务器接收。 我正在使用函数recv

接收发生在仅当从客户端接收到终止请求时退出的循环中。

服务器代码:

// Request Winsock version 2.2 fprintf(stderr,"Performing WSAStartup\n"); if ((retval = WSAStartup(0x202, &wsaData)) != 0) { fprintf(stderr,"FAILED with error %d\n", retval); WSACleanup(); return -1; } else { printf("OK\n"); } if (port == 0) { Usage(argv[0]); } /* open socket connection */ printf("Opening socket\n"); local.sin_family = AF_INET; local.sin_addr.s_addr = (!ip_address) ? INADDR_ANY:inet_addr(ip_address); /* Port MUST be in Network Byte Order */ local.sin_port = htons(port); // TCP socket listen_socket = socket(AF_INET, socket_type,0); if (listen_socket == INVALID_SOCKET){ fprintf(stderr,"socket() failed with error %d\n", WSAGetLastError()); WSACleanup(); return -1; } else { printf("OK\n"); } // bind() associates a local address and port combination with the socket just created. // This is most useful when the application is a // server that has a well-known port that clients know about in advance. printf("Bind address and port to socket\n"); if (bind(listen_socket, (struct sockaddr*)&local, sizeof(local)) == SOCKET_ERROR) { fprintf(stderr,"bind() failed with error %d\n", WSAGetLastError()); WSACleanup(); return -1; } else { printf("OK\n"); } // So far, everything we did was applicable to TCP as well as UDP. // However, there are certain steps that do not work when the server is // using UDP. We cannot listen() on a UDP socket. if (socket_type != SOCK_DGRAM) { printf("TCP: listening on socket\n"); if (listen(listen_socket,5) == SOCKET_ERROR) { fprintf(stderr,"listen() failed with error %d\n", WSAGetLastError()); WSACleanup(); return -1; } else { printf("OK\n"); } } //Perform Applcation task //initisations printf("Server is listening and waiting for a connection\non port %d, protocol %s\n",port, (socket_type == SOCK_STREAM)?"TCP":"UDP"); executeServer = 1; while(executeServer == 1) { fromlen =sizeof(from); // accept() doesn't make sense on UDP, since we do not listen() if (socket_type != SOCK_DGRAM) { printf("TCP: Waiting for connection (accept())\n"); msgsock = accept(listen_socket, (struct sockaddr*)&from, &fromlen); if (msgsock == INVALID_SOCKET) { fprintf(stderr,"accept() error %d\n", WSAGetLastError()); WSACleanup(); return -1; } else { printf("OK\n"); printf("accepted connection from %s, port %d\n", inet_ntoa(from.sin_addr), htons(from.sin_port)) ; } } else { msgsock = listen_socket; } // In the case of SOCK_STREAM, the server can do recv() and send() on // the accepted socket and then close it. // However, for SOCK_DGRAM (UDP), the server will do recvfrom() and sendto() in a loop. printf("Receiving data"); if (socket_type != SOCK_DGRAM) { retval = recv(msgsock, Buffer, sizeof(Buffer), 0); } else { retval = recvfrom(msgsock,Buffer, sizeof(Buffer), 0, (struct sockaddr *)&from, &fromlen); printf("Received datagram from %s\n", inet_ntoa(from.sin_addr)); } if (retval == SOCKET_ERROR) { fprintf(stderr,"recv() failed: error %d\n", WSAGetLastError()); closesocket(msgsock); return -2; } else { printf("OK\n"); } if (retval == 0) { printf("Client closed connection.\n"); closesocket(msgsock); } else { printf("Received %d bytes, data \"%s\" from client\n", retval, Buffer); } printf("Processing Data\n"); if (!stricmp(Buffer, "exit")) { wsprintf(AckBuffer,"ACK"); executeServer = 0; } else { // Perform use task here based on recieved data } printf("Sending answer to client\n"); if (socket_type != SOCK_DGRAM) { retval = send(msgsock, AckBuffer, sizeof(AckBuffer), 0); } else { retval = sendto(msgsock, AckBuffer, sizeof(AckBuffer), 0, (struct sockaddr *)&from, fromlen); } if (retval == SOCKET_ERROR) { fprintf(stderr,"send() failed: error %d\n", WSAGetLastError()); } else { printf("OK\n"); } /* close TCP connection */ if (socket_type != SOCK_DGRAM) { closesocket(msgsock); } } printf("terminating server\n"); closesocket(msgsock); WSACleanup(); 

客户代码:

  fprintf(stderr,"Performing WSAStartup"); if ((retval = WSAStartup(0x202, &wsaData)) != 0) { fprintf(stderr,"WSAStartup() failed with error %d\n", retval); WSACleanup(); return -1; } else { printf("OK\n"); } if (port == 0) { Usage(argv[0]); } // Attempt to detect if we should call gethostbyname() or gethostbyaddr() printf("Translate hastname to address -> gethostbyaddr()\n"); if (isalpha(server_name[0])) { // server address is a name hp = gethostbyname(server_name); } else { // Convert nnn.nnn address to a usable one addr = inet_addr(server_name); hp = gethostbyaddr((char *)&addr, 4, AF_INET); } if (hp == NULL ) { fprintf(stderr,"Cannot resolve address \"%s\": Error %d\n", server_name, WSAGetLastError()); WSACleanup(); exit(1); } else { printf("OK\n"); } // Copy the resolved information into the sockaddr_in structure printf("Opening socket\n"); memset(&server, 0, sizeof(server)); memcpy(&(server.sin_addr), hp->h_addr, hp->h_length); server.sin_family = hp->h_addrtype; server.sin_port = htons(port); conn_socket = socket(AF_INET, socket_type, 0); /* Open a socket */ if (conn_socket <0 ) { fprintf(stderr,"Error Opening socket: Error %d\n", WSAGetLastError()); WSACleanup(); return -1; } else { printf("OK\n"); } // Notice that nothing in this code is specific to whether we // are using UDP or TCP. // We achieve this by using a simple trick. // When connect() is called on a datagram socket, it does not // actually establish the connection as a stream (TCP) socket // would. Instead, TCP/IP establishes the remote half of the // (LocalIPAddress, LocalPort, RemoteIP, RemotePort) mapping. // This enables us to use send() and recv() on datagram sockets, // instead of recvfrom() and sendto() printf("Client connecting to: %s.\n", hp->h_name); if (connect(conn_socket, (struct sockaddr*)&server, sizeof(server)) == SOCKET_ERROR) { fprintf(stderr,"connect() failed: %d\n", WSAGetLastError()); WSACleanup(); return -1; } else { printf("OK\n"); } /* copy options string to buffer */ strcpy(Buffer,Options); printf("Sending Data \"%s\"\n", Buffer); retval = send(conn_socket, Buffer, sizeof(Buffer), 0); if (retval == SOCKET_ERROR) { fprintf(stderr,"send() failed: error %d.\n", WSAGetLastError()); WSACleanup(); return -1; } else { printf("OK\n"); } printf("Receiving status from server\n"); retval = recv(conn_socket, Buffer, sizeof(Buffer), 0); if (retval == SOCKET_ERROR) { fprintf(stderr,"recv() failed: error %d.\n", WSAGetLastError()); closesocket(conn_socket); WSACleanup(); return -1; } else { printf("OK\n"); } // We are not likely to see this with UDP, since there is no // 'connection' established. if (retval == 0) { printf("Client: Server closed connection.\n"); closesocket(conn_socket); WSACleanup(); return -1; } printf("Received %d bytes, data \"%s\" from server.\n", retval, Buffer); closesocket(conn_socket); WSACleanup(); 

如果你不使用套接字非阻塞模式而使用recv ,那么你的recv就是在做一件正确的事情。 它阻塞,直到有东西要读。

[UPDATE]

从代码,你确实使用阻塞套接字。 我建议你至少为你的服务器使用非阻塞套接字。 我相信你可以很容易地谷歌如何使非阻塞套接字和处理Windows中的异步IO。 祝你好运!

[UPDATE2]

首先,一旦recv读取一些东西,你的服务器代码似乎关闭连接。 由于TCP不关心数据边界,所以不能关闭连接。 请记住,客户端的一个send呼叫可能需要服务器与TCP的多个recv呼叫,反之亦然。

对于你的具体问题,我敢肯定,没有什么可读的,这就是为什么recv阻止你的程序。 确保你的客户确实发送了一些东西。