.net 异步TCP服务器代码示例分析

xt0899hw  于 2023-05-19  发布在  .NET
关注(0)|答案(1)|浏览(116)

我使用以下代码创建一个异步TCP服务器:

private void SetupServerSocket()
{
    var myEndpoint = new IPEndPoint(IPAddress.Any, _port);

    _serverSocket = new Socket(myEndpoint.Address.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
    _serverSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true);
    _serverSocket.Bind(myEndpoint);
    _serverSocket.Listen((int)SocketOptionName.MaxConnections);
}

protected void Open()
{
    SetupServerSocket();
    Opened = true;
    _serverSocket.BeginAccept(AcceptCallback, _serverSocket);
}

private void AcceptCallback(IAsyncResult result)
{
    var connection = new ConnectionInfo();
    try
    {
        // Finish Accept
        var s = (Socket)result.AsyncState;
        connection.Socket = s.EndAccept(result);
        connection.Buffer = new byte[8192];

        lock (_connections)
        {
            _connections.Add(connection);
        }

        // Start Receive and a new Accept
        connection.Socket.BeginReceive(connection.Buffer, 0, connection.Buffer.Length, SocketFlags.None, ReceiveCallback, connection); 
        _serverSocket.BeginAccept(AcceptCallback, result.AsyncState);
    }
    catch (SocketException ex)
    {
        CloseConnection(connection);
    }
    catch (Exception ex)
    {
        CloseConnection(connection);
    }
}

private void CloseConnection(ConnectionInfo ci)
    {
        if (ci.Socket != null)
        {
            if (OnDisconnect != null)
                OnDisconnect.Invoke((IPEndPoint)ci.Socket.RemoteEndPoint);

            ci.Socket.Shutdown(SocketShutdown.Both);
            ci.Socket.Close();
        }

        lock (_connections)
        {
            _connections.Remove(ci);
        }
    }

有些事情很难理解:
1 -使用_serverSocket.SetSocketOption启用了TCP中的KeepAlive。我发现Windows默认的KeepAlive Timer为2小时!并且使用Wireshark证实了该行为。
经过一些谷歌搜索,我发现在http://support.microsoft.com/kb/120642/EN-US,你可以改变Windows KeepAliveTime通过创建一个键在注册表中。我喜欢这个支持页面的指示,但KeepAlive计时器没有应用(即使重新启动后),它仍然是2小时。有人知道如何在Windows中更改KeepAlive定时器吗?
2 -代码connection.Socket = s.EndAccept(result)可以抛出异常(通常是SocketException)。为什么Socket.EndResult抛出SocketException
3 -如果AcceptCallback()已经处于接受状态,为什么我们必须在AcceptCallback()中再次将_serverSocket设置为接受状态?

6jjcrrmo

6jjcrrmo1#

1.我在.net的Keep Alive计时器上也遇到了类似的问题。我从来没有找到一种方法来改变它,所以我们使用的解决方案是有一个后台工作线程,在给定的时间段后,如果其他真实的数据没有发送,它会发送少量数据,通常是byte[1]

  1. EndAccept()可以按照MSDN抛出预期的异常。这些通常发生在套接字在其他地方发生了一些事情的情况下,例如套接字被关闭等。您需要正确地捕获这些异常并决定希望程序如何继续。在您的情况下,它看起来像您只是关闭连接。
    1.调用_serverSocket.BeginAccept(AcceptCallback, result.AsyncState);只会对最先接受的连接触发一次回调。在此之后,您必须决定是否要接受未来的进一步连接,如果是,则在回调中再次调用BeginAccept。

相关问题