Mangos 之 AuthSocket模块
(1)AuthSocket从TcpSocket继承而来,在TcpSocket中处理具体的网络读写任务(OnRead),将数据读入并存放到循环缓冲区,然后AuthSocket的OnRead()会将循环缓冲区中的
数据解析出来并调用响应的处理函数处理。
(2)mangos在TcpSocket中采用循环缓冲区来存放接收到或待发送出去的数据,所以也要进行crosses circular border处理。这样只有在跨越边界的时候,才会多调用一次memcpy;
另外一种处理方式是每次将数据移动到缓冲区头部,其实这样可能会导致更多的memcpy调用,效率应该不如前一种方式。
在向循环缓冲区中写数据时,如果循环缓冲区中空间不够,数据将被丢弃,而不放入缓冲区中。我想到了一种极端情况,比如缓冲区中哈剩下20字节空间,而新的用户数
据来了,数据包的大小是30字节,由于网络原因被分包发送过来了,先到了15字节,这时剩余空间可以放下这15字节;而另外半个包之后猜到,这时缓冲区中已经没有空间了,所
以后半个包就将被丢弃;这时缓冲区中的包就不完整了。
其实,这个问题可以通过一种简单方式进行处理,即调用recv时,就将最大的接收字节数设置成循环缓冲区的空闲空间大小,但是mangos没有这么做。
(3)在Auth模块中的协议有多种,mangos将协议码和处理函数指针放到一个结构中统一管理,如:
typedef struct AuthHandler
{
eAuthCmd cmd;
uint32 status;
bool (AuthSocket::*handler)(void);
}AuthHandler;
定义:
const AuthHandler table[] =
{
{ AUTH_LOGON_CHALLENGE, STATUS_CONNECTED, &AuthSocket::_HandleLogonChallenge},
{ AUTH_LOGON_PROOF, STATUS_CONNECTED, &AuthSocket::_HandleLogonProof },
{ REALM_LIST, STATUS_AUTHED, &AuthSocket::_HandleRealmList },
{ XFER_ACCEPT, STATUS_CONNECTED, &AuthSocket::_HandleXferAccept },
{ XFER_RESUME, STATUS_CONNECTED, &AuthSocket::_HandleXferResume },
{ XFER_CANCEL, STATUS_CONNECTED, &AuthSocket::_HandleXferCancel }
};
调用:
if ((uint8)table[i].cmd == _cmd &&
(table[i].status == STATUS_CONNECTED ||
(_authed && table[i].status == STATUS_AUTHED)))
{
if (!(*this.*table[i].handler)())
{
return;
}
}
在AuthSocket的OnRead函数中,只会把第一个字节取出来,即协议命令的类型,然后更加协议命令在table中找到对应的处理函数接口,在具体的协议处理函数中,处理函数根据自己的协议体规范从循环缓冲区中读数据并做处理。
我们自己的做法通常是有一套协议解析,编解码函数,会把完整的协议体解析出来,然后根据具体的协议类型调用不同的函数来处理;但是在这里,mangos没有采用这种方式,而是只在公共的部分解析大家公共的cmd信息,其他具体的信息,甚至包括协议体长度这些私人东西都交给具体的处理函数来解决,有点“个人自扫门前雪”的感觉,但是这样有一个好处就是在需要添加协议的时候,我只需要实现新的协议的解析处理接口,并在table中添加一项即可;如果采用专门解析协议体的方式,那么就会多修改一个地方,即在协议解析的代码部分需要加入新协议的解析,处理部分也需要加入新的代码,多了一个修改的地方,多了一个烦恼,也多了一个出错的可能。
(4)mangos怎么判断网络卡的?
“TCP_BUFSIZE_READ-GetOutputLength()< 2*ChunkSize”
TCP_BUFSIZE_READ是网络连接循环缓冲区最大长度(16400Bytes),
GetOutputLength()表示当前发送缓冲区中累计了多少字节没有发送出去。
ChunkSize 2048Bytes
即当前发送缓冲区中的空闲空间小于2个ChunkSize就认为网络卡了。
阅读(1508) | 评论(0) | 转发(0) |