套接字编程C/ c++ - recv函数在服务器端挂起
Socket Programming C/C++ - recv function hangs in Server
我在使用recv函数时遇到问题
我有一个应用程序,从客户端发送一些数据,这些数据被服务器接收&发送基于数据的响应。
当我发送少于16个请求时,实现工作正常。但是当我从客户端发送超过16个请求(一个接一个)时,服务器的响应很好,直到第16个请求,但在此之后服务器挂起。我可以看到数据是从客户端发送的,但是服务器没有接收到。我正在使用函数recv
接收发生在一个循环中,只有当从客户端接收到终止请求时才退出。
服务器代码: // Request Winsock version 2.2
fprintf(stderr,"Performing WSAStartupn");
if ((retval = WSAStartup(0x202, &wsaData)) != 0)
{
fprintf(stderr,"FAILED with error %dn", retval);
WSACleanup();
return -1;
}
else
{
printf("OKn");
}
if (port == 0)
{
Usage(argv[0]);
}
/* open socket connection */
printf("Opening socketn");
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 %dn", WSAGetLastError());
WSACleanup();
return -1;
}
else
{
printf("OKn");
}
// 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 socketn");
if (bind(listen_socket, (struct sockaddr*)&local, sizeof(local)) == SOCKET_ERROR)
{
fprintf(stderr,"bind() failed with error %dn", WSAGetLastError());
WSACleanup();
return -1;
}
else
{
printf("OKn");
}
// 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 socketn");
if (listen(listen_socket,5) == SOCKET_ERROR)
{
fprintf(stderr,"listen() failed with error %dn", WSAGetLastError());
WSACleanup();
return -1;
}
else
{
printf("OKn");
}
}
//Perform Applcation task
//initisations
printf("Server is listening and waiting for a connectionnon port %d, protocol %sn",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 %dn", WSAGetLastError());
WSACleanup();
return -1;
}
else
{
printf("OKn");
printf("accepted connection from %s, port %dn", 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 %sn", inet_ntoa(from.sin_addr));
}
if (retval == SOCKET_ERROR)
{
fprintf(stderr,"recv() failed: error %dn", WSAGetLastError());
closesocket(msgsock);
return -2;
}
else
{
printf("OKn");
}
if (retval == 0)
{
printf("Client closed connection.n");
closesocket(msgsock);
}
else
{
printf("Received %d bytes, data "%s" from clientn", retval, Buffer);
}
printf("Processing Datan");
if (!stricmp(Buffer, "exit"))
{
wsprintf(AckBuffer,"ACK");
executeServer = 0;
}
else
{
// Perform use task here based on recieved data
}
printf("Sending answer to clientn");
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 %dn", WSAGetLastError());
}
else
{
printf("OKn");
}
/* close TCP connection */
if (socket_type != SOCK_DGRAM)
{
closesocket(msgsock);
}
}
printf("terminating servern");
closesocket(msgsock);
WSACleanup();
客户机代码: fprintf(stderr,"Performing WSAStartup");
if ((retval = WSAStartup(0x202, &wsaData)) != 0)
{
fprintf(stderr,"WSAStartup() failed with error %dn", retval);
WSACleanup();
return -1;
}
else
{
printf("OKn");
}
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 %dn", server_name, WSAGetLastError());
WSACleanup();
exit(1);
}
else
{
printf("OKn");
}
// Copy the resolved information into the sockaddr_in structure
printf("Opening socketn");
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 %dn", WSAGetLastError());
WSACleanup();
return -1;
}
else
{
printf("OKn");
}
// 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: %dn", WSAGetLastError());
WSACleanup();
return -1;
}
else
{
printf("OKn");
}
/* 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("OKn");
}
printf("Receiving status from servern");
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("OKn");
}
// 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
正在做正确的事情。它会阻塞,直到有东西可读。
从代码中,您确实使用了阻塞套接字。我建议您至少对您的服务器使用非阻塞套接字。我相信你可以很容易地谷歌如何在Windows中制作非阻塞套接字和处理异步IO。好运!
(更新2)首先,你的服务器代码似乎关闭连接一旦recv
读的东西。由于TCP不关心数据边界,所以不能直接关闭连接。请记住,客户机中的一个send
调用可能需要使用TCP在服务器中调用多个recv
,反之亦然。
对于你的具体问题,我很确定没有什么可读的,这就是为什么recv
阻止你的程序。请确保您的客户端确实成功发送了一些内容。
相关文章:
- 服务器端事件C++实现?
- 如何使用 GRPC c++ 读取异步服务器端流
- QAbstractSocket 从服务器端关闭连接时的奇怪行为
- 从服务器端关闭主套接字
- 在GRPC服务器端呼叫时检索SSL证书
- BLE在Linux环境中使用C++的服务器端实现
- 如何在服务器端验证用户请求(在我的特定情况下)
- 如何检测端口是否已在服务器端使用(在windows上的C++中)
- RPC C++服务器端动态终结点
- 如果另一侧失去了他的净连接,我该如何从客户端/服务器端检测
- 如何使用php级别以下的代码进行服务器端编程
- 在没有 SO_LINGER > 0 的情况下强制关闭服务器端套接字可能会丢失数据,对吧?
- 提升ASIO TCP,为什么我不能在服务器端只有一个数据套接字可以打开和关闭
- FTP服务器端口处于主动模式和被动模式
- MongoDB C++驱动程序服务器端查询计数
- CORBA C++/Java应用程序中服务器端的分段故障(核心转储)
- 正在比较服务器端收到的字符串-C++
- 如何在boostc++中添加http服务器端口的路径
- MySQL 服务器端超时
- 套接字编程C/ c++ - recv函数在服务器端挂起