第一章、简介(抛出问题)
参考: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
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