逐步实现TCP服务端Step04-2:处理client断开

当某个client断开连接时,后端系统要做相应的“清理”工作。具体说来就是netio要销毁TCPSocket对象,s要销毁用户对象。

问题在于,client断开连接,s是不知道的,除非netio以某种方式告知它。

可以在c2s_code_queue中push一个特殊的code以表明某个client已经离线了。这样,一旦s取到该code就触发”清理“操作。

这个特殊的code其实不用专门去设计。考虑一下client断开时,TCP的做法是向对端发送一个不携带数据的报文段,这样对端的TCP数据接收接口就会返回0,即:拿到了报文段,但没有数据。我们在构造这个特殊的code时,可以沿用TCP的做法,只给出NetHead首部即可,s在提取该code时,发现其只有NetHead部分,就认为该客户已经离线了,然后启动”清理“工作。

那么s到底要做什么呢?简单明了的方式就是使用某些方法直接把client对应的用户对象给Destroy掉。目前的情况这么做是可以的,因为s仅仅是做echo服务,本身没有复杂的逻辑,其所做的工作在自己的UserObject对象中就能完成。但是,如果s处理的业务,需要多个对象协作完成的话,就不可简单粗暴的“就地”销毁UserObject对象。因为在销毁的那一刻,它可能正在参与某些业务,就这么不声不响的消失了,那些依赖于它的对象应如何应对?

这就好比某人要从公司离职,在向负责人提出申请并获批后,一声不吭地直接走人。

合理的做法是,离开前应与其他同事进行交流,至少是在工作上有依赖关系的那些人。把与他人相关的工作收一下尾,做个交代,不能撒手不管,影响他人的工作进度。

如果把公司看成一个系统的话,离职就是从系统中logout出去。从公司走人则是logout的最后一步,即:销毁对象。

s也应该这么做,当得知有client关闭时,首先要触发logout流程,当然,也可就地做一些自我清理工作,类似于现实中的收拾东西。只有当logout流程完全结束后,才可对UserObject对象实施销毁。

对于logout,可以复用其它流程,不必单独设计。考虑一下,client的离线方式其实有两种,第一种就是我们现在讨论的client主动关闭连接的情况;另一种则是client向后端发送logout消息,要求下线,此时后端会执行logout流程,并通知client可以下线,然后client再关闭连接。

从client的角度看,这两种方式都达到了离线的目的,没有什么区别。从后端的角度,尤其是业务层面来看,第一种属于“非法”离线。就像直接拔电源关机一样,机器是关掉了,但没走系统的关机流程。

“合法”离线,由client主动发出logout消息,“非法”离线则client不发logout消息。它不发的话,我们就自己构造一个logout消息追加到消息队列中,这样就实现了对logout流程的复用。

新版主流程:

此次新增及改动的文件:


<==  index  ==>