【问题标题】:Winsock not sending in a while loopWinsock 没有在 while 循环中发送
【发布时间】:2013-03-13 11:05:23
【问题描述】:

我对网络非常陌生,并且在 while 循环期间发送消息时遇到问题。

据我所知,我应该这样做:

Create Socket()
Connect()

While
     Do logic
     Send()
End while

Close Socket()

但是它发送一次然后返回-1。

代码只有在我在循环中创建套接字时才会起作用。

While
     Create Socket()
     Connect()
     Do logic
     Send()
     Close Socket()
End while

这是我正在使用但不起作用的代码部分:

//init winsock
WSAStartup(MAKEWORD(2, 0), &wsaData);

//open socket
    sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);

    //connect
    memset(&serveraddr, 0, sizeof(serveraddr));
    serveraddr.sin_family      = AF_INET;
    serveraddr.sin_addr.s_addr = inet_addr(ipaddress);
    serveraddr.sin_port        = htons((unsigned short) port);
    connect(sock, (struct sockaddr *) &serveraddr, sizeof(serveraddr));

while(true) {

    if (send(sock, request.c_str(), request.length(), 0)< 0 /*!= request.length()*/) {
        OutputDebugString(TEXT("Failed to send."));
    } else {
        OutputDebugString(TEXT("Activity sent."));
    }
    Sleep(30000);
}
//disconnect
closesocket(sock);

//cleanup
WSACleanup();

函数CheckForLastError()返回:10053

WSAECONNABORTED 软件导致连接中止。 已建立的连接被主机中的软件中止,可能是由于数据传输超时或协议错误

谢谢

【问题讨论】:

  • connect 也应该在 while 循环之外。您能否展示您遇到问题的示例?
  • 正确的方法是第一个示例中的方法,它只发送一次然后返回错误。您应该致电WSAGetLastError 来获取该错误,这应该会提示您失败的原因。您的第二个示例仅因为您在重复第一个示例而起作用;创建套接字,连接,发送,关闭套接字,回到第一步。
  • 该IP地址是否在监听任何流量?
  • 你研究过WSAECONNABORTED是什么意思吗?这可能会为您提供如何进行的线索
  • 将您最后的 request+="\r\n"; 更改为 request+="\r\n\r\n";HTTP 需要 double newline 来结束请求,而你只发送一个,所以 HTTP 服务器就在等你完成发送。

标签: c++ windows sockets networking winsock


【解决方案1】:

我也一直在寻找解决这个问题的方法。我的服务器也有同样的问题。当尝试从循环内部发送响应时,客户端似乎永远不会收到它。

据我了解问题,根据user207421的建议,当您在客户端和服务器之间建立连接时,协议应该有足够的信息让客户端知道服务器何时完成发送响应。如果您看到此example,则您有一个响应请求的最小 HTTP 服务器。在这种情况下,您可以使用浏览器或 Postman 等应用程序。如果您看到响应消息,您将看到一个名为Connection 的标头。将其值设置为close 会告诉客户端哪个是来自服务器的该请求的最后一条消息。消息正在发送,但客户端一直在等待,可能是因为客户端无法识别关闭元素。我也错过了Content-Length 标头。我的 HTTP 响应消息错误,客户端丢失了。

此图显示了需要在循环之外以及需要在循环内部的内容。

【讨论】:

  • 不必在每次响应时关闭连接。然而,客户端必须在每个响应的流结束之前不要读取。相反,双方都需要遵守一个应用程序协议,在该协议下他们可以知道每条消息的结束位置。
  • 这听起来很合理,但完成后关闭连接似乎是唯一能发送信息的东西,“这就是我为你准备的一切,客户!”。使用浏览器访问端点时,屏幕上显示内容,但通信保持打开状态,浏览器一直等待。对 Insomnia 这样的程序做同样的事情也不起作用。该程序一直在等待,没有显示任何答案。您能否测试附加到此特定案例答案的代码?这里应该是正确的“沟通结束”?
  • 还是错了。我已经说明了您真正的问题:您的客户端必须一直读取到流结束,如果服务器在响应后没有关闭,则永远不会到达。以下只是一些在每次响应后都不会关闭的知名协议:HTTP、FTP、TLS、RMI、IIOP、SMTP、POP3、IMAP……我可以继续。我不是来测试其他人答案中的代码,其他人也不是。
  • 注意我看了你的链接。它只包含一个服务器。不是问题的现场。关闭套接字不会强制将任何内容发送到另一端,但实际的关闭位除外。
  • 对不起,你是对的。在这里检查代码不应该是任何人的任务。我问的不好?我知道你想告诉我什么,我将重写我给出的答案。你帮了我很多,@ user207421。谢谢?
【解决方案2】:

要了解程序失败的方式和原因,您必须了解您使用的功能。 其中一些是阻塞功能,而另一些则不是。其中一些需要先前调用其他函数,而另一些则不需要。 现在据我了解,我们在这里谈论的是客户端,而不是服务器。 在这种情况下,客户端只有非阻塞功能。这意味着每当您调用一个函数时,它都会在不等待的情况下执行。 所以 send() 将在它被调用的第二次发送数据,并且流将继续到下一行代码。 如果要发送的信息还没有准备好……你会遇到问题,因为什么都不会发送。 要解决它,您可以使用某种延迟。延迟的问题在于它们是阻塞函数,这意味着您的流一旦达到延迟就会停止。要解决它,您可以创建一个线程并将其锁定,直到准备好发送信息。 但这将完成一个 send() 的工作。您将发送信息,仅此而已。 如果要保持通信并重复发送信息,则需要创建一个while循环。一旦你有一个while循环,你就不必担心任何事情。那是因为您可以使用流控制验证信息是否已准备就绪,并且您可以在终止连接之前反复使用发送。 现在的问题是服务器端发生了什么? “ipaddress”应该保存服务器的 ip。服务器可能会拒绝您的连接请求。或者最糟糕的是,他可能会接受您的请求,但他正在使用与您的客户端相关的不同设置进行侦听。这意味着服务器可能没有接收(没有 recv() 函数)信息,而您正在试图发送信息......这可能会导致错误/崩溃等等。

【讨论】:

  • "在这种情况下客户端只有非阻塞函数" - socket() 创建一个默认以阻塞模式运行的新套接字。所以send() 将阻塞直到它的工作完成。要获得您描述的那种非阻塞行为,您必须明确地将套接字置于非阻塞模式,例如使用 ioctlsocket(FIONBIO)
猜你喜欢
  • 1970-01-01
  • 2013-09-28
  • 1970-01-01
  • 2017-03-19
  • 1970-01-01
  • 2012-05-22
  • 1970-01-01
  • 2017-01-05
  • 2019-10-11
相关资源
最近更新 更多