C/C++套接字编程 - recv函数卡住了?

10

我的recv函数在从服务器获取响应时挂起。

C / C ++中的客户端代码:

void sockStuff() {

 int sock, bytes_recieved,bytes_send;
 char send_data[1024], recv_data[4096];

 struct hostent *host;
 struct sockaddr_in server_addr;

 host = gethostbyname("127.0.0.1");

 if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
  perror("SocketError");
  exit(1);
 }
 server_addr.sin_family = AF_INET;
 server_addr.sin_port = htons(50500);
 server_addr.sin_addr = *((struct in_addr *) host->h_addr);
 bzero(&(server_addr.sin_zero), 8);


 if (connect(sock, (struct sockaddr *) &server_addr, sizeof(struct sockaddr))
   == -1) {
  perror("ConnectToError");
  exit(1);
 }


    bytes_send = send(sock, a, strlen(a), 0);
    bytes_send = shutdown(sock, 1);


 bytes_recieved = recv(sock, recv_data, 4096, 0); //Where the program hangs??
 recv_data[bytes_recieved] = '\0';
 printf("\nRecieved data = %s ", recv_data);
 cout << endl << endl;

 shutdown(sock,2);



}

我的客户端是C/C++,服务器端是OpenEdge Progress。 请看代码并建议出了什么问题。??


1
你应该使用sizeof(server_addr.sin_zero)而不是神奇数字8。或者更好的方法是将整个结构清零,然后设置你感兴趣的字段。 - anon
嗨Neil,你能否详细说明一下这个问题?因为我尝试了sizeof(server_addr.sin_zero),而不是数字8,但仍然没有成功。谢谢。 - Vishal
6个回答

8

您的代码将在recv调用中阻塞,直到服务器发送任何数据回来。既然这种情况没有发生,也许您应该问问自己是否客户端已经发送完整的请求。服务器可能不会开始发送响应,直到接收到完整的请求为止。

如果您的客户端/服务器协议是基于文本的,例如HTTP或SMTP,您确定您的响应正确终止了吗?服务器可能期望CR + LF('\r\n')而不仅仅是LF('\n'),或者它期望一个空行来终止请求:

char *request = "GET /index.html HTTP/1.1\r\nHost: www.example.com\r\n\r\n";

提示:在您的代码片段中没有声明或初始化'a'。


5

您的代码将在recv调用中阻塞,直到服务器发送任何数据回来。由于这并没有发生,也许您应该问问自己是否客户端已经发送了完整的请求。收到完整请求后,服务器可能不会开始发送响应。

如果您的客户端/服务器协议是基于文本的,比如HTTP或SMTP,您确定您的响应正确终止吗?服务器可能期望CR+LF('\r\n')而不仅仅是LF('\n'),或者它希望通过一个空行终止请求:

char *request = "GET /index.html HTTP/1.1\r\nHost: www.example.com\r\n\r\n"; PS. 您在代码片段中未声明或初始化'a'。

我正在使用c++进行早期winsock 1.0和1.1实现的副本。我的代码一直工作到recv()调用,然后就停在那里...我知道阻塞非阻塞套接字,但这不是我需要的解决方案。由于我看到了我的请求在wireshark或类似软件中,我知道服务器正在端口80上接收到我的字符串请求,而我的代码在'net上的客户端和服务器之间没有通信而在recv()调用中冻结。 这使我相信我没有提交适当的请求。作者(notaket)说得对!一旦我改用他的请求( "GET /index.html HTTP/1.1\r\nHost: www.example.com\r\n\r\n"),一切似乎都像魔法一样工作!谢谢!


2

recv 应该一直等待,直到从服务器接收到响应。你是否说明了响应正在发送中。
尝试使用Wireshark或类似工具来嗅探网络并查看实际响应是否已经到达。


实际上,在recv()挂起后,我尝试了ctrl+alt+del。通过执行此操作,任务管理器打开,但我关闭了该任务管理器(未杀死任何进程),突然它给了我响应。但是我的程序仍处于冻结状态。 - Vishal

1

嗯...你为什么关闭了socket....

bytes_send = send(sock, a, strlen(a), 0);
    bytes_send = shutdown(sock, 1); /*** 我认为这就是问题所在! ***/
bytes_recieved = recv(sock, recv_data, 4096, 0);

然而你在代码中继续从同一个被关闭的socket接收数据?

希望这能给你指明正确的方向。


感谢Tom的回复。但是shutdown(sock, 1);并没有关闭套接字,它只是告诉发送操作被禁止(没有更多数据可以发送)。即使我删除这行代码,我的recv()函数仍然会挂起。 - Vishal
@Vishal:好的...http://www.developerweb.net/forum/showthread.php?t=2940 - 这里有一个关于何时使用shutdown的有趣讨论。代码是同步模式,可能在shutdown之前已经接收到数据并因此挂起。你有考虑过这个问题吗?如果我没有什么帮助的话,对不起... :( - t0mm13b

1

如果套接字处于阻塞模式,Recv将阻塞直到套接字有可读信息,您可以使用fcntl更改此模式。

如果你想知道为什么它会挂起,我的猜测是当你关闭套接字上的写入管道时(另外,你可能想使用常量SHUT_WR,因为它更好看),服务器收到EOF并假定你正在断开连接,尽管如果服务器设置为处理它,则可能不是这种情况。

我建议研究将套接字设置为非阻塞模式,然后调用select,它将阻塞直到套接字可读/可写或触发超时。根据你所做的事情,这将产生不同的影响。


1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接