C#TcpSockets我是否断开干净/正确的方式?

时间:2014-09-19 11:46:57

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

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

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

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

在客户端,我有一些麻烦,了解我如何得到断开我相信正在发生的事情如下:在我的异步接收回调我应该得到一个错误,因为服务器启动关机序列,我必须处理那个(对吧???)所以我的客户端代码看起来像这样: ReceiveCallback:

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);
    }

DisconnectCallback

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

(断开连接方法是重载的,所以如果我得到一个异常它会发出一个messageBox,然后也会调用Disconnect。就这样我知道发生了什么。)

我错在哪里,我能改善什么?

我尝试了代码,它似乎工作,但我看了netstat,如果所有套接字都关闭,客户端套接字不是。它在FIN_WAIT_2中意味着它(或服务器???)还没有发送FIN数据包吗? 哦,然后我再次尝试了这条线改变了:

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

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

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

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

2 个答案:

答案 0 :(得分:1)

您的正常断开连接已关闭,这将清除套接字,以便它可以正常断开,但您的异步样式永远不会调用shutdown。我将它添加到下面方便的位置。

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

答案 1 :(得分:1)

重要的是:

  • 如果服务器启动关闭序列,则必须处理它
  • 双方都必须在他们的套接字上调用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