逐步实现TCP服务端Step03-1:封装TCPSocket类


这是一些枚举所表示的意义:

SetNonBlock方法:对应于SetSockNonBlock函数,实现上做了一些修改,一开始没必要判断传入的socket文件描述符的正负,fcntl函数自会给出结果,关注其返回值即可。另外,O_NDELAY是SystemV系统中定义的一个flag,这里把它也考虑上。

Accept后得到的新的用于通信的socket会被设置为no-block,还有connect成功以后,socket也会被设置为no-block。CreateServer以及CreateClient所创建的socket都是block类型。

RecvBytes方法:对应于RecvBytes函数,逻辑是一样的。

GetOneCode方法:OnRecvdSocketBytesEx函数做了两件事情:1. 从接收buffer中按规则提取出code;2. 将code入队到code队列中。对于TCPSocket类来说,只做第一项工作(GetOneCode)就行了,至于入队的动作则应该由队列类来完成。

SendOneCode方法:它的语义是发出“一个”code,对调用者来说,使用该方法就意味着可以把整个code都发出去。即使出现发送不完整的情况(TCP缓冲区空间不足),也不应该让调用者处理。因此,SendOneCode要加入Reserve机制,将未发出的残留字节保存起来,SendOneCode应先调用SendBytes尝试发送那些Reserve字节。

这个方法最后的参数is_reserve用来指定是否要reserve未发出去的code,注意,粒度是”code”不是“字节”。所谓的“未发出去”是指code中没有一个字节发出去,它是一个完整的code,此时,若设置is_reserve为false,SendOneCode将不会对该code进行reserve,置为true则相反。而如果code中至少有一个字节已被发出,此时,剩余的字节已不能构成一个完成的code,那么,此时的is_reserve不论是true还是false,剩余的code字节都会被reserve。

is_reserve只对完整的code起作用:

ReserveBytes方法:将指定的字节存入post_buf_中,SendOneCode时若有残留字节,就使用ReserveBytes把残留字节存放起来,待下次发送。

再明确一下几个关键方法的工作过程

RecvBytes : 

GetOneCode : 

SendOneCode : 在正式发送code之前,会先尝试发送滞留的字节(存在于post_buf_中),如果出现TCP发送缓冲区满的情况,就基于is_reserve标记来决定是否reserve待发送的code。在枚举SendErrors中,列出了ERR_SEND_NOTCPBUFF,即TCP发送缓冲区已满。在基于非阻塞socket的send操作中,TCP发送缓冲区满不该视为错误,这里枚举ERR_SEND_NOTCPBUFF主要是为SendBytes方法准备的,SendBytes以这个枚举值告知SendOneCode方法TCP发送缓冲已满,此时的SendOneCode不应将其视为错误,返回0即可。

TCPSocket类的实现详见:tcpsocket.htcpsocket.cc文件,同时netio.ccc.cc中的部分内容已改用TCPSocket来实现。

<==  index  ==>