使用心跳机制实现CS架构下多客户端的在线状态实时更新以及掉线自动重连

此文讲述的内容是一个实际项目开发中的一部分内容,笔者将亲身经历写成文章。

【背景】

现需要实现这样的功能:有多个客户端连着同一个服务器。服务器和客户端之间需要“互相”知道彼此的连接状态。比如在某一时刻,服务器需要知道当前有多少个客户端正在和其通信;某一个时刻,某个客户端需要知道自己是否和服务器保持连接。如果在某一时刻,一个客户端关闭了,服务端应能及时感觉到;同样,如果服务端被关闭,所有的客户端应能及时感觉到,并作出一些反应。

【思考】

看到这个需求,直观上的反应就是在服务端维护一个在线列表。当服务端的监听器监听到一个连接,就把该连接对应的客户端信息加入这个在线列表。这样就完成了对上线状况的记录。但下一个问题是如何让服务器知道客户端的离线状况呢?我们可能会想到,让客户端在关闭前发送一个消息到服务端,服务端收到消息后就把客户端置为离线状态。但是,在更多情况下,客户端并不是这么“友好”地关闭的。应用程序崩溃、网络连接被重置、机器死机等情况下,客户端来不及发送“离线通知”给服务端就挂掉了。这时,需要有一套机制,能让服务端和客户端彼此对对方的在线状态保持清醒。

【概念】

何谓“心跳”? 心跳就是指“活着”的客户端或服务端每隔一定的时间就互相发送接收一个消息,告诉对方自己“活着”。当客户端或服务端超过一定的时间间隔尚未收到对方的“心跳”消息,就认为对方“死了”。这就是“心跳机制”的核心思想。

【设计实现】

在客户端,除了 UI 外,需要三个线程在后台工作。

1,自动连接的线程。该线程可以实现每隔指定时间就检查一次连接状态,如果发现当前是“离线”状态,就自动发起向服务端的一次连接。

  1         private void ThreadConnect()

 2          {
 3               do
 4              {
 5 
 6                   if  ( ! _bConnected)
 7                  {
 8                      _bConnected  =  _sender.Connect(_ip, _port);
 9 
10                       if  (_bConnected)
11                      {
12 
13                          Thread threadSendAndReceivePulseMessage  =   new  Thread( new  ThreadStart(ThreadSendAndReceivePulseMessage));
14                          threadSendAndReceivePulseMessage.IsBackground  =   true ;
15                          threadSendAndReceivePulseMessage.Start();
16 
17                          Thread threadCheckPulseCount  =   new  Thread( new  ThreadStart(ThreadCheckPulseCount));
18                          threadCheckPulseCount.IsBackground  =   true ;
19                          threadCheckPulseCount.Start();
20 
21                          _pulseCount  =   0 ;
22 
23                          OnConnected( new  EventArgs());
24                      }
25 
26                  }
27                  Thread.Sleep(_connectInterval);
28 
29              }
30               while  (_bWorking  &&  _bAutoReconnect);
31          }

 

 2,收发“心跳”消息的线程。该线程和服务端进行收发心跳消息。注意每收到服务器发来的消息,应将心跳计数器置零。心跳计数器的含义是已经隔了多少个心跳周期没收到心跳消息了。

 

  1         private void ThreadSendAndReceivePulseMessage()

 2          {
 3               while  (_bWorking  &&  _bConnected)
 4              {
 5 
 6                   string  recv  =   _sender.Receive( 64 );
 7 
 8 
 9                   if  (recv  ==   " PULSE " )
10                  {
11                      _pulseCount  =   0 ;
12 
13                      _sender.Send( " ALIVE " );
14                  }
15                   else
16                  { 
17                      _bConnected  =   false ;
18                      _sender.Close();
19                      
20                  }
21                  Thread.Sleep( 10 );
22              }
23          }

 

 3,检查心跳计数器的值的线程。该线程每隔指定的时间间隔就检查一次心跳计数器,当发现已经超过指定心跳周期(比如3次)未接收到心跳消息,就认为是离线了,则进行相应的处理。

 

  1         private void ThreadCheckPulseCount()

 2          {
 3               while  (_bWorking  &&  _bConnected)
 4              {
 5                  Thread.Sleep(_pulseInterval);
 6 
 7                  _pulseCount ++ ;
 8 
 9                   if  (_pulseCount  >  _maxPulseCount)
10                  {
11                      _bConnected  =   false ;
12                      _sender.Close();
13                  }
14 
15                   if  ( ! _bConnected)
16                  {
17                      OnDisconnected( new  EventArgs());
18                  }
19              }
20          }

 

 

 在服务端,设计思想类似,需要维护一个“在线列表”,并及时和客户端通信,此处省略代码。

【运行结果与测试】

开启服务端,并开启13个客户端(为了测试联机的时候的工作情况,使用了虚拟机,在本机上开了6个客户端,虚拟机里开了7个客户端)。

 

 使用心跳机制实现CS架构下多客户端的在线状态实时更新以及掉线自动重连_第1张图片

 

 此时关闭服务端,可以看到,所有的客户端都掉线了。

 

使用心跳机制实现CS架构下多客户端的在线状态实时更新以及掉线自动重连_第2张图片 

 再次启动服务端,此时所有的客户端都自动地连接。

 

 使用心跳机制实现CS架构下多客户端的在线状态实时更新以及掉线自动重连_第3张图片

 

 仔细观察,连接的顺序每次并不相同,这是正常的。

直接关闭所有的客户端。观察服务端的输出。

 

 使用心跳机制实现CS架构下多客户端的在线状态实时更新以及掉线自动重连_第4张图片

 

 服务端也能感知所有的客户端的离线情况。离线的顺序和上线的顺序并不一定一致,这是正常的。

over..

 

 

 

 

 

 

你可能感兴趣的:(客户端)