【问题标题】:C# TcpSockets Do I disconnect the clean/proper way?C# TcpSockets 我是否以干净/正确的方式断开连接?
【发布时间】:2014-09-22 19:16:34
【问题描述】:

所以我知道有很多关于这个主题的文章,我确实阅读了很多我想说的但由于某种原因我确定我的代码没有做它应该做的事情。

我想关闭我的服务器和我的客户端之间的连接。 现在在服务器端我用这段代码开始断开连接

public void shutdown()
    {
        _socket.Shutdown(SocketShutdown.Both);
        _socket.Close();
    }

在客户端,我在理解如何断开连接时遇到了一些麻烦,我认为正在发生以下情况:在我的异步接收回调中,我应该收到一个错误,因为服务器启动了关闭序列,我必须处理那(对???)所以我的客户端代码如下所示: 接收回调:

private void ReceiveCallback(IAsyncResult result)
    {
        int bytesRecieved = 0;
        byte[] tempBuff;

        //Try to receive But if a Socket error occures disconnect otherwise start Receiving again
        try
        {
            bytesRecieved = _socket.EndReceive(result);
        }
        catch (SocketException sockEx)
        {
            Disconnect(sockEx);
            return;
        }
        catch (ObjectDisposedException disposeEx)
        {
            Disconnect(disposeEx);
            return;
        }
        catch (Exception ex)
        {
            StartReceive();
            return;
        }

        if (bytesRecieved == 0)
        {
            StartReceive();
            return;
        }

        tempBuff = new byte[bytesRecieved];
        Buffer.BlockCopy(_buffer, 0, tempBuff, 0, bytesRecieved);
        StartReceive();
        _packHandler.handlePacket(tempBuff);

    }

断开连接:

public void Disconnect()
    {
        if (!_socket.Connected)
        {
            return;
        }
        _socket.BeginDisconnect(false, DisconnectCallback, null);
    }

断开回调

private void DisconnectCallback(IAsyncResult result)
    {
        _socket.EndDisconnect(result);
        _socket.Close();
    }

(Disconnect 方法超载,所以如果我遇到异常,它会创建一个 messageBox,然后还会调用 Disconnect。这样我就知道发生了什么。)

我哪里错了,我可以改进什么???

我尝试了代码,它似乎可以工作,但我随后使用 netstat 查看是否所有套接字都已关闭并且客户端套接字没有。它在 FIN_WAIT_2 中,这意味着它(或服务器???)还没有发送 FIN 数据包,对吗? 哦,然后我又试了一次,换了这条线:

if (bytesRecieved == 0)
        {
            StartReceive();
            return;
        }

if (bytesRecieved == 0)
        {
            Disconnect;
            return;
        }

然后在服务器端和客户端抛出异常,客户端说连接已被服务器关闭???

编辑:即使我关闭了两个程序 Netstat 仍然显示端口处于等待状态。这告诉我什么?

【问题讨论】:

    标签: c# sockets visual-studio-2013 .net-4.5 asyncsocket


    【解决方案1】:

    您的正常断开连接有一个关闭,它将清除套接字,以便它可以正确断开连接,但您的异步样式从不调用关闭。我将它添加到下面一个方便的位置。

    public void Disconnect()
    {
        if (!_socket.Connected)
        {
            return;
        }
        _socket.Shutdown(SocketShutdown.Both); // Make sure to do this
        _socket.BeginDisconnect(false, DisconnectCallback, null);
    }
    

    编辑:

    从听起来你没有理由使用异步方法?异步方法使您可以在单独的执行线程中发送数据,从而释放您的线程以进行一些数据处理,例如在发生这种情况时。

    我没有看到任何处理正在进行,所以我建议您像这样更改断开连接,看看它是否能解决问题。因为我不认为您正在等待效果不佳的 Async 方法。

    public void Disconnect()
    {
        if (!_socket.Connected)
        {
            return;
        }
        shutdown(); //Your standard disconnect that you showed up top.  Scoping might be required.
    }
    

    Async 的一些数据可以在这里找到:http://msdn.microsoft.com/en-us/library/38dxf7kt(v=vs.110).aspx

    【讨论】:

    • 好的,谢谢您的回复。你能解释一下当我调用shutdown时会发生什么,然后beginDisconnect会发生什么,同步套接字和异步套接字之间的区别是什么?
    • 更新:我试过了,但套接字仍然打开。编辑:现在我的服务器也崩溃了,异常说客户端在我停止服务器的那一刻就关闭了连接
    • 我认为您使用的 Async 方法以一种糟糕的方式混合在一起,而不是等待它们。无论如何,我在上面编辑并解释了一些。
    • 好吧,我想你是对的,我不想再做任何处理,所以我把它改回同步,我仍然在 FIN_WAITING_2 中有一个打开的套接字,尽管如果我关闭客户端应用程序,它会进入 WAITING 编辑:但是如果我在客户端关闭后添加一行 _socket.Close() 并且在那一刻我的服务器崩溃,但如果你用 netstat 查看它说连接状态是 CONNECTED ????跨度>
    • 您的关闭函数中有一个 _socket.Close(),因此再次调用它会产生异常。
    【解决方案2】:

    重要的是:

    • 如果服务器启动关闭序列,您必须处理它
    • 双方都必须在他们的套接字上调用shutdown
    • 您需要一种方法来发现断开连接(它不会给您一个错误,或者至少对我来说没有)

    为此,我创建了自己的类 customSocket,它继承自 Socket

    public class customSocket : Socket
    {
        #region Properties
        private readonly Timer _timer;
        private const int _interval = 1000;
    
        private bool Connected
        {
            get
            {
                bool part1 = Poll(1000, SelectMode.SelectRead);
                bool part2 = (Available == 0);
                if (part1 && part2)
                    return false;
                else 
                    return true;
            }
        }
    
        public bool EventsEnabled
        {
            set
            {
                if (value)
                {
                    _timer.Start();
                }
                else
                    _timer.Stop();
            }
        }
    
        #endregion
    
        #region Constructors
    
        public customSocket(AddressFamily addressFamily, SocketType sockType, ProtocolType protocolType)
            : base(addressFamily, sockType, protocolType)
        {
            _timer = new Timer { Interval = _interval };
            _timer.Elapsed += TimerTick;
        }
    
        public customSocket(SocketInformation sockInfo)
            : base(sockInfo)
        {
            _timer = new Timer { Interval = _interval };
            _timer.Elapsed += TimerTick;
        }
    
        #endregion
    
        #region Events
    
        public event EventHandler<EventArgs> Socket_disconected;
        public void Raise_Socket_disconnected()
        {
            EventHandler<EventArgs> handler = Socket_disconected;
            if (handler != null)
            {
                handler(this,new EventArgs());
            }
        }
    
        private void TimerTick(object sender, EventArgs e)
        {
            if (!Connected)
            {
                Raise_Socket_disconnected();
            }
        }
    
        #endregion
    }
    

    这个版本的套接字有一个用于断开连接的事件。 现在,如果您创建套接字类的实例,则必须连接处理程序并将 EventsEnabled 设置为 true。

    此处理程序然后调用关闭,您的套接字不会停留在 FIN_WAIT_2

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-03-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多