gpt4 book ai didi

c++ - 套接字编程 C/C++ - recv 函数在服务器中挂起

转载 作者:太空宇宙 更新时间:2023-11-04 04:04:54 25 4
gpt4 key购买 nike

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

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

当我发送少于 ~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 是正确的。它会阻塞,直到有内容可读为止。

[更新]

从代码来看,您确实使用了阻塞套接字。我建议您至少为您的服务器使用非阻塞套接字。我相信您可以轻松地通过谷歌搜索如何在 Windows 中制作非阻塞套接字和处理异步 IO。祝你好运!

[更新2]

首先,您的服务器代码似乎在 recv 读取内容后关闭连接。由于 TCP 不关心数据边界,您不能只关闭连接。请记住,客户端中的一次 send 调用可能需要在服务器中使用 TCP 进行多次 recv 调用,反之亦然。

对于您的具体问题,我很确定没有什么可读的,这就是 recv 阻止您的程序的原因。确保您的客户真的成功发送了一些东西。

关于c++ - 套接字编程 C/C++ - recv 函数在服务器中挂起,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7314909/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com