“现有连接被远程主机强行关闭".在侦听传入数据时

问题描述:

在使用Boost asio时,我偶然发现了一些我不太了解的奇怪行为.我编写了一个最小的测试程序来复制该问题:

When working with boost asio, I've stumbled upon some weird behavior, which I don't quite understand. I wrote a minimal test-program to replicate the problem:

#include <boost/asio.hpp>
#include <iostream>

using boost::asio::ip::udp;

int main(int argc,char *argv[])
{
    boost::asio::io_service ioService;
    udp::resolver resolver(ioService);

    udp::resolver::query queryListen("127.0.0.1","50001");
    auto epListen = *resolver.resolve(queryListen);
    udp::socket socket(ioService,epListen);

    udp::resolver::query querySend("127.0.0.1","55006");
    auto epSend = *resolver.resolve(querySend);
    boost::system::error_code err;
    std::array<char,12> buffer = {'1','2','3','4','5','6','7','8','9','10','11','12'};
    socket.send_to(
        boost::asio::buffer(&buffer[0],buffer.size()),
        epSend,0,err
    );
    if(!err)
    {
        std::cout<<"Sent successfully!"<<std::endl;
        auto numBytes = socket.receive(
            boost::asio::buffer(&buffer[0],buffer.size()),0,
            err
        );
        if(!err)
            std::cout<<"Received "<<numBytes<<" bytes successfully!"<<std::endl;
        else
            std::cout<<"Unable to receive: "<<err.message()<<std::endl; // This is where I'm getting the message "An existing connection was forcibly closed by the remote host"
    }
    else
        std::cout<<"Unable to send: "<<err.message()<<std::endl;
    for(;;);
    return 0;
}

如果"send_to"呼叫的目标端点存在并且正在侦听,则此程序运行良好.数据已正确发送,然后等待传入数据.

If the destination endpoint for the 'send_to'-call exists and is listening, this program runs just fine. The data is sent correctly, and it then waits for incoming data.

但是,如果目标端点不存在,则该行为非常意外. 'send_to'调用仍会分派数据,而没有任何错误,但是当尝试接收数据时,'receive'调用会立即返回,并且我收到现有连接被远程主机强行关闭"错误.这对我来说没有任何意义.首先,没有远程主机,因为没有数据发送到侦听器端口.其次,据我了解,该程序的接收部分和发送部分应该是完全独立的,并且互不影响.我在这个假设上错了吗?

However, if the destination endpoint doesn't exist, the behavior is rather unexpected. The 'send_to'-call still dispatches the data without any errors, but when trying to receive data, the 'receive'-call immediately returns, and I'm getting a "An existing connection was forcibly closed by the remote host" error. This doesn't make any sense to me. First of all, there is no remote host, since there is no data being sent to the listener port. Secondly, from what I understand, the receiving- and the sending-part in this program should be completely independent, and shouldn't affect each other at all. Am I wrong in that assumption?

//

我刚刚意识到,该消息没有任何意义还有另一个原因.我使用的是无连接的UDP procotol,那么什么连接"已关闭?

I've just realized that there's another reason why that message doesn't make any sense. I'm using the UDP procotol, which is connectionless, so what 'connection' was closed?

虽然UDP通常被称为无连接协议,但上下文暗示了无状态协议.因此,允许 UDP 返回一些与连接相关的错误消息:

While UDP is often referred to as a connectionless protocol, the context implies a stateless protocol. As such, UDP is permitted to return some connect-related error messages:

针对 socket

All errors documented for socket or ip may be returned by a send or receive on a UDP socket.

ECONNREFUSED
   没有接收者与目标地址相关联.这可能是由通过套接字发送的上一个数据包引起的.

ECONNREFUSED
    No receiver was associated with the destination address. This might be caused by a previous packet sent over the socket.

The Winsock recvfrom() 函数记录了有关UDP的信息,如果先前的发送操作导致ICMP端口不可达消息,该函数将以WSAECONNRESET错误出现:

The Winsock recvfrom() function documents that for UDP, the function will error with WSAECONNRESET if a prior send operation resulted in an ICMP Port Unreachable message:

WSAECONNRESET
    [...]在UDP数据报套接字上,此错误表明先前的发送操作导致了ICMP端口不可达消息.

WSAECONNRESET
    [...] On a UDP-datagram socket this error indicates a previous send operation resulted in an ICMP Port Unreachable message.