逐步实现TCP服务端Step02-3:继续改进

经过改造,主流程中的RecvBytes、GetOneMessage和SendBytes都不会引起阻塞。只有ProcessOneMessage存在阻塞的可能。

ProcessOneMessage中有潜在的“长操作”,例如:磁盘I/O、大量的计算等。若服务端在Process一个消息的时候进行了这种“长操作”,那么主流程就没法快速的进行下去了。

考虑到数据的收发都是在这个主流程成中完成的。Process ...


逐步实现TCP服务端Step02-2:改进

到目前为止服务端处理消息的情况是这样的:

先从socket缓冲中尽力取字节,把取到的字节放到一个单字节数组中去(recv字节队列)。然后,从这个数组中取字节,组成消息。

每次要发送消息时,都要先尝试发送post字节队列中残留的字节,然后再去发送本次实际要发送的字节。如果此次发送没有将期望的字节量全部发出,就把剩余的字节存到post队列中,等待下次调用SendOneMessageEx时再尝试发送。

发送字节的操作是在SendOneMessageEx中进行的,如果SendOneMessageEx不被调用的话,残留的字节就没机会被发送。这个地方不太合理,说白了SendOneMessageEx也应该拆成两个过程 ...


逐步实现TCP服务端Step02-1:基于非阻塞socket的处理逻辑

把socket设置成非阻塞,其目的就是不让程序逻辑在网络I/O处阻塞不前。整个程序都将基于这个“不阻塞”的大前提来进行设计。基于非阻塞socket调用recv和send时不会阻挠逻辑向前进行,那么,其包装函数RecvOneMessage和SendOneMessage也要做到不阻挠才合适。否则,若使用这组包装函数去替换原始函数,程序的行为就有可能会偏离我们的预期。

RecvOneMessage函数内部是循环操作,达到目标有可能要进行多次循环。同时,对于阻塞式socket来说,一次循环中的recv调用又有可能发生阻塞。这么看来基于阻塞式socket的RecvOneMessage函数是有可能阻挠逻辑前进的。

那么,基于非阻塞socket的情况呢 ...


逐步实现TCP服务端:index


TCP半关闭的必要性

TCP所提供的是全双工服务(数据可在两个方向上同时传递),连接建立后,就如同开辟了两条通路。对连接的任一端来说,一条通路用于进数据,另一条用于出数据。 一般说关闭TCP连接,是指某一端调用了close(windows平台为closesocket)函数将自己的两条通路同时断开,其结果就是,它再也不可在socket上收发数据了(TCP会将那些已在发送缓冲中的数据发送出去 ...


硬性关闭TCP连接

硬性关闭是指:使用非正常的手法立即终止当前TCP连接,只求关闭,不考虑后果,丢失数据也无所谓。这种方式在处理一些紧急状况时或许是必要的。

正常的关闭流程是在连接双方的配合下经历四次握手完成的。应用程序里的操作就是调用close接口。

对socket实施close操作,实际上会产生一个FIN报文段,这个段当然也要遵从TCP的规则,它会在发送缓冲区中排队。显然,调用close的一方要想实际发出这个FIN段,当然要先将排在它之前的那些字节发出去才行。也就是说,调用close后,到实际发出FIN之前,发送缓冲区中的数据已经发送到对端了。

上面说的是正常的关闭,用close接口即可发起。非正常关闭,也是用这个接口,只不过要配置一下socket的LINGER选项。

linger有“苟延残喘”的意思 ...