简体   繁体   English

调用 EndAccept 并访问 RemoteEndPoint 后套接字未连接异常

[英]Socket not connected exception after calling EndAccept and accessing RemoteEndPoint

When accessing the RemoteEndPoint property of an accepted socket on the server, a SocketException: 'The socket is not connected' is sometimes thrown.访问服务器上已接受套接字的 RemoteEndPoint 属性时,有时会抛出 SocketException: 'The socket is not connected'。

This happens occasionally (like once in 100 connection attempts) and only when there is a significant latency over the network (eg 10ms+, wifi network).这种情况偶尔会发生(例如 100 次连接尝试中发生一次),并且仅在网络上存在显着延迟时(例如 10 毫秒以上、wifi 网络)。 Seems to be some kind of race condition but I'm not sure what can be done to prevent this.似乎是某种竞争条件,但我不确定可以做些什么来防止这种情况。

Server code:服务器代码:

this.Socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
this.Socket.Bind(new IPEndPoint(IPAddress.Parse("0.0.0.0"), port));
this.Socket.Listen(0);
this.Socket.BeginAccept(OnSocketAccepted, null);

private void OnSocketAccepted(IAsyncResult ar)
{
    var socket = Socket.EndAccept(ar);
    var endPoint = socket.RemoteEndPoint; // SocketException: The socket is not connected
}

Client code:客户端代码:

var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socket.Connect(ip, port);
// times out after a couple of seconds if the exception happened on the server

Server is running on Mono 6.4.0.198 on ARMv7 rev4 Raspberry Pi 3b+服务器在 ARMv7 rev4 Raspberry Pi 3b+ 上的 Mono 6.4.0.198 上运行

Client is running on Windows 10 .NET framework 4.6.1 console app客户端在 Windows 10 .NET framework 4.6.1 控制台应用程序上运行

I thought EndAccept basically guaranteed that the socket would be in a connected state and the RemoteEndPoint would be set.我认为 EndAccept 基本上可以保证套接字处于连接状态并且 RemoteEndPoint 将被设置。 I've gone through the whole msdn EndAccept and RemoteEndPoint documentation and can't find any obvious mistakes or misunderstandings.我已经浏览了整个 msdn EndAccept 和 RemoteEndPoint 文档,但找不到任何明显的错误或误解。

The Socket can close after you have called EndAccept() and before you have queried RemoteEndPoint. Socket 可以在您调用 EndAccept() 之后和查询 RemoteEndPoint 之前关闭。 It can also close before your callback calls EndAccept(), this will also throw a Socket Exception.它也可以在您的回调调用 EndAccept() 之前关闭,这也会引发 Socket 异常。

There aa number of race conditions that can happen in here, particularly if your system is slow.这里可能会发生许多竞争条件,特别是如果您的系统很慢。 You can check Socket.Connected but even that isn't guaranteed.您可以检查 Socket.Connected 但即使这样也不能保证。

The correct approach is a Try/Catch and gracefully exit or throw an unrecoverable socket.正确的方法是 Try/Catch 并优雅地退出或抛出不可恢复的套接字。

eg,例如,

        catch (SocketException ex)
        #region SocketException
        {
            /// Some SocketExceptions we manage quietly.  Others we surface as critical errors.
            if ((SocketError)ex.ErrorCode == SocketError.AddressAlreadyInUse)
            {
                Log.Error("Endpoint failed to start. IPEndPoint {ipEndPoint} already in use.", this.localIPEndPoint.ToString());
                // Execution will continue after finally{}
            }
            else
            {
                Log.Error(ex, "Endpoint has ended with an unrecoverable socket error:", Name);
                throw;
            }
        }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM