Bootstrap

Socket 中级篇(一)Socket断开后要自动重连的常用几种方法:Connected、心跳包、recv()返回值==-1等等。

第一章、简介(抛出问题)

    参考:https://www.cnblogs.com/youxin/p/4056041.html

     功能方面比较简单就是client端与server端建立连接,然后发送消息给server。我在server端会使用专门的线程处理一条socket连接。这就涉及到一个问题,如果socket连接断开(异常,正常)后,我如何才能感知到?server端这边是绝对被动的,sever端不能主动断开连接。也没有连接链路维持包之类的。client端发送数据的时间也是不定的。在socket连接断开后, server要能够感知到并释放资源。

1.1、服务器如何判断客户端与服务端是否断开?

       往往来说,服务器是不会断开,我们经常要考虑的是客户端的断开重连问题。

     方法1:发心跳包(超时未回复则断开,释放宽带等资源)

       客户端定时(比如30s发一次)地发心跳包给服务端,服务器给客户端发一个响应信号。如果服务器没有收到心跳包,那就是掉线了。这时候,我们就要释放该用户的资源。待客户端连接请求的时候,我们再建立一个Socket对象给该用户,即重新建立连接。

       参考:https://q.cnblogs.com/q/63760/

    方法2: Client.Receive()== 0(简单便捷、资源不缺情况下可用该方法)

       客户端连接状态有数据接收,Receive返回值 > 0。连接状态无数据接收,Receive会一直等待,不存在返回值的说明。断开状态下 Receive返回值 == 0。

      所以,我们可以用 Receive返回值 == 0判断是否断开。

    方法3:select()返回值==1,且recv()返回值为0 

     参考https://www.cnblogs.com/ranjiewen/p/5723936.html(这篇博客提供了5种方法)

         https://www.cnblogs.com/jacklikedogs/p/3976208.html

    方法四:socket.Poll()方法+Connected属性

参考:https://www.cnblogs.com/cuisir/p/8522680.html

https://blog.csdn.net/phker/article/details/71169887

if (list[i].Poll(1000, SelectMode.SelectRead)) 
//SelectMode.SelectRead表示,如果已调用 并且有挂起的连接,true。
//- 或 - 如果有数据可供读取,则为 true。- 或 - 如果连接已关闭、重置或终止,则返回 true(此种情况就表示若客户端断开连接了,则此方法就返回true); 否则,返回 false。
{
     list[i].Close();//关闭socket
     list.RemoveAt(i);//从列表中删除断开的socke
     continue;
}           

  方法五:socket类Connected属性

在断开状态下,Connected = false

在连接状态下, Connected = true

1.2、我该用哪种方法来判断?

       不是所有的方法都适合自己的场景,带宽等资源足够、用户链接较少的情况下,建议采用第一章的方法2。否则,若是服务器级别,由于资源比较珍贵,用户比较多,建议采用方法1。

二、我的实现思路(Client.Receive()== 0 + Client.Connected ==false)

参考:

https://blog.csdn.net/lexjay/article/details/80535030

http://www.7kb.org/313.html重点

https://blog.csdn.net/u014722754/article/details/51318583(重点重点)

经过我的测试,采用(Client.Receive()== 0 + Client.Connected ==false)两者结合的方式,可以解决自动重连问题。

我们必须注意:

A、当正常连接状态,且服务器没有给客户端发数据时。  循环扫描一直停留在iRecBuffeActualByteCount = Client.Receive(btRecBuffer);这一步,知直到收到服务发过来的数据为止。(后面我们会附上全部代码)

B、一旦服务器断开,那么iRecBuffeActualByteCount就等于0,即iRecBuffeActualByteCount ==0。也就是说,我们可以通过判断iRecBuffeActualByteCount == 0 ,然后执行自动重连的方法。(后面我们会附上全部代码)

C、断开瞬间Client.Receive()== 0,但是 Client.Connected ==true。经过一会后, Client.Connected才等于false。

所以我们不能单单用 Client.Connected==false判断是否断开,这点是特别需要注意的。

 

2.1、步骤一

定义断开重连的方法,返回Socket。

        /// <summary>
        /// 断开重连
        /// </summary>
        /// <param name="socketVar"></param>
        /// <returns></returns>
        private Socket ReConnet(Socket socketVar)
        {
            Socket Client = socketVar;
            //bool blIsConneted = false;
            if (Client != null)
            {
                Client.Connect(serverIPEndPoint);
                MessageBox.Show("连接不上,自动重连");
            }
            if (Client.Connected == false)
            {
                Client.Connect(serverIPEndPoint);
                //开启线程,消息框
                MessageBox.Show("连接不上,点击重连");
            }
            return Client;
        }

在接收端,把这个方法用起来:

 但是该方法会报错,错误信息:

       断开套接字连接后,只能通过异步方式再次重新连接,而且只能连接到不同的 EndPoint。在操作完成前,在将不会退出的线程上必须调用 BeginConnect。

        因为套接字断开后,不能通过同步的方式,再次连接到同一个EndPoint。在该方法中,断开连接后,我们还是用了之前的Client对象。所以,该方法不可用。那么我们的解决方法是,在方法二里面,重新创建一个Client对象,并重新请求连接。

https://blog.csdn.net/baronyang/article/details/72779761

https://blog.csdn.net/phker/article/details/71169887

https://bbs.csdn.net/topics/370176926

方法二、重新创建一个Client对象,并重新请求连接

        网上,有很多人遇到同样的问题,不解释了,自己上代码。

https://blog.csdn.net/baronyang/article/details/72779761

https://www.cnblogs.com/friendan/archive/2012/06/03/2838167.html

 

 

;