C# 中socket根据Receive判断 TcpClient关闭连接的处理

C# 中socket根据Receive判断 TcpClient关闭连接的处理

程序脚手架

在C#中,开发网络应用,.Net Framework提供了各种便利。
- TcpListener用于服务端的监听服务。
- TcpClient 用于网络客户端的便利开发

服务端和客户端网络连接后,进行数据通信。

其中服务端的接收程序框架如下:

while (true)
{
    try
    {
        byte[] buffer = new byte[1024];
        int count = socket.Receive(buffer);
        // ......
        // 对接收到数据进行处理
    }
    catch (SocketException ex)
    {
        int err = ex.ErrorCode;
        string str = socket.RemoteEndPoint.ToString();
        logger.Warn(str + " socketErrorCode: "+ err+ " -- exception:  " + ex.Message);
        // ... ... 处理
    }
    catch(ObjectDisposedException closedException)
    {
        logger.Error(closedException);

        // ... ... 处理

        break;
    }
    catch (Exception ex)
    {
        logger.Error(ex);
        // ... ... 处理
    }    
}

如果通信完成,需要结束,进行连接关闭。这是如果TcpClient进行关闭操作

tcpClient.Close();
tcpClient.Dispose();

问题

这里期望在客户端主动关闭后,服务端的socket会得到异常,然后在异常中进行后续处理,比如关闭服务端的对应socket,释放分配的数据缓冲器……。

但发现了一个问题,客户端TcpClient关闭后,接收处理线程并没有异常抛出。

Receive函数

在Socket类中,Receive函数是一个阻塞操作,没有数据receive到,则会阻塞。在接收到数据后,函数返回。
函数的说明如下:

        //
        // 摘要:
        //     从绑定接收数据 System.Net.Sockets.Socket 到接收缓冲区中。
        //
        // 参数:
        //   buffer:
        //     类型的数组 System.Byte ,它是接收到的数据的存储位置。
        //
        // 返回结果:
        //     收到的字节数。
        //
        // 异常:
        //   T:System.ArgumentNullException:
        //     buffer 为 null。
        //
        //   T:System.Net.Sockets.SocketException:
        //     尝试访问套接字时出错。 有关详细信息,请参阅备注部分。
        //
        //   T:System.ObjectDisposedException:
        //     System.Net.Sockets.Socket 已关闭。
        //
        //   T:System.Security.SecurityException:
        //     调用堆栈中的调用方没有所需的权限。
        public int Receive(byte[] buffer);

当然可以设置receive的socket的receive-timeout;这样在timeout后,会有SocketExcept发生。但这个异常并不是客户端主动关闭或者网络中断。

       //
        // 摘要:
        //     获取或设置一个值,指定的后的时间量同步 Overload:System.Net.Sockets.Socket.Receive 调用将会超时。
        //
        // 返回结果:
        //     超时值(以毫秒为单位)。 默认值为 0,表示超时期限无限。 指定-1 还指示超时期限无限。
        //
        // 异常:
        //   T:System.Net.Sockets.SocketException:
        //     尝试访问套接字时出错。
        //
        //   T:System.ObjectDisposedException:
        //     System.Net.Sockets.Socket 已关闭。
        //
        //   T:System.ArgumentOutOfRangeException:
        //     设置操作为指定的值是小于-1。
        public int ReceiveTimeout { get; set; }

但是如果连接的客户端主动关闭后,Receive函数会理解返回,而且返回值为0;这时就表示客户端主动关闭了。

如果此时服务端不关闭,则对应的网络连接处于 FIN_WAIT_2,CLOSE_WAIT状态,如图。
网络关闭残留
此时,服务端执行相应的socket关闭操作,就可以正常关闭连接了,否则,会有socket残余留下。正常关闭下的结果,如图:
无关闭残余

  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值