📄 csdn_文档中心_myicq情景分析.htm
字号:
<P style="MARGIN-BOTTOM: 0px; MARGIN-TOP: 0px">void
handlePacket()<BR>{<BR>240 int sock =
UdpSession::sock;<BR>241<BR>242 for (;;)
{<BR>243 fd_set
readfds;<BR>244
fd_set
writefds;<BR>245<BR>246
FD_ZERO(&readfds);<BR>247
FD_ZERO(&writefds);<BR>248<BR>249
FD_SET(sock,
&readfds);<BR>250
int maxfd =
sock;<BR>251<BR>252
if (_ops.enableS2S)
{<BR>253
int n = Server::generateFds(readfds,
writefds);<BR>254
if (n >
maxfd)<BR>255
maxfd = n;<BR>256
}<BR>257<BR>258
timeval to;<BR>259
to.tv_sec =
1;<BR>260 to.tv_usec
= 0;<BR>261<BR>262
int n = select(maxfd + 1, &readfds, &writefds, NULL,
&to);<BR>263<BR>264
if (n > 0)
{<BR>265
if (FD_ISSET(sock,
&readfds))<BR>266
UdpSession::onReceive();<BR>267<BR> </P>
<P
style="MARGIN-BOTTOM: 0px; MARGIN-TOP: 0px">此函数用了winsock中的select模型,有to所以为非阻塞状态如发现有未读入的数据就调用UdpSession::onReceive()来处理,我们继续,</P>
<P
style="MARGIN-BOTTOM: 0px; MARGIN-TOP: 0px">handlePacket()->UdpSession::onReceive(</P>
<P style="MARGIN-BOTTOM: 0px; MARGIN-TOP: 0px">bool
UdpSession::onReceive()<BR>{<BR>852 char
buf[UDP_PACKET_SIZE];<BR>853 sockaddr_in
addr;<BR>854 socklen_t len =
sizeof(addr);<BR>855 int n = recvfrom(sock,
buf, UDP_PACKET_SIZE, 0, (sockaddr *) &addr,
&len);<BR>856<BR>857 if (n < (int)
sizeof(UDP_CLI_HDR))<BR>858
return false;<BR>859<BR>860 UdpInPacket
in(buf, n);<BR>861<BR> </P>
<P
style="MARGIN-BOTTOM: 0px; MARGIN-TOP: 0px">855-858从指定的sock中接收到字符后,建立一个UdpInPacket对象,它的继承关系是UdpInPacket->IcqInPacket->InPacket,构造函数如下</P>
<P style="MARGIN-BOTTOM: 0px; MARGIN-TOP: 0px">IcqInPacket(char *d,
int n) <BR>{<BR> cursor = data = (uint8 *)
d;<BR> datalen = n;<BR>}</P>
<P style="MARGIN-BOTTOM: 0px; MARGIN-TOP: 0px"> </P>
<P
style="MARGIN-BOTTOM: 0px; MARGIN-TOP: 0px">UdpInPacket::UdpInPacket(char
*d, int n):IcqInPacket(d, n)<BR>{<BR> *this
>> header.ver >> header.reserved;<BR>
*this >> header.uin >> header.sid >>
header.cmd;<BR> *this >> header.seq >>
header.cc;<BR>}</P>
<P style="MARGIN-BOTTOM: 0px; MARGIN-TOP: 0px">UDP_CLI_HDR
header;</P>
<P style="MARGIN-BOTTOM: 0px; MARGIN-TOP: 0px">struct UDP_CLI_HDR
{<BR> uint16 ver;<BR> uint32
reserved;<BR> uint32 uin;<BR>
uint32 sid;<BR> uint16 cmd;<BR>
uint16 seq;<BR> uint16 cc; // check code<BR>};</P>
<P style="MARGIN-BOTTOM: 0px; MARGIN-TOP: 0px">InPacket
&IcqInPacket::operator >>(uint8
&b)<BR>{<BR> b = 0;<BR> if
(cursor <= data + datalen - sizeof(b))<BR> b =
*cursor++;<BR> return *this;<BR>}<BR>InPacket
&IcqInPacket::operator >>(uint16
&w)<BR>{<BR> w =
ntohs(read16());<BR> return
*this;<BR>}<BR>InPacket &IcqInPacket::operator >>(uint32
&dw)<BR>{<BR> dw =
ntohl(read32());<BR> return
*this;<BR>}<BR>InPacket &IcqInPacket::operator >>(ICQ_STR
&str)<BR>{<BR> uint16
len;<BR> operator
>>(len);<BR><BR> if (len && cursor
<= data + datalen - len && !cursor[len - 1])
{<BR> str.text = (char *)
cursor;<BR> str.len = len
- 1;<BR> cursor +=
len;<BR> } else
{<BR> str.text =
"";<BR> str.len =
0;<BR> }<BR> return
*this;<BR>}</P>
<P style="MARGIN-BOTTOM: 0px; MARGIN-TOP: 0px">uint16
IcqInPacket::read16()<BR>{<BR> uint16 w =
0;<BR> if (cursor <= data + datalen -
sizeof(w)) {<BR> w = *(uint16 *)
cursor;<BR> cursor +=
sizeof(w);<BR> }<BR> return
w;<BR>}<BR>uint32 IcqInPacket::read32()<BR>{<BR>
uint32 dw = 0;<BR> if (cursor <= data + datalen
- sizeof(dw)) {<BR> dw =
*(uint32 *) cursor;<BR> cursor +=
sizeof(dw);<BR> }<BR> return
dw;<BR>}</P>
<P
style="MARGIN-BOTTOM: 0px; MARGIN-TOP: 0px">上面函数的大概意思就是通过运算符重载把读入的数据从网络字节转换为主机字节后赋给UdpInPacket类的公有成员变量header;</P>
<P
style="MARGIN-BOTTOM: 0px; MARGIN-TOP: 0px">让我们继续UdpSession::onReceive()</P>
<P
style="MARGIN-BOTTOM: 0px; MARGIN-TOP: 0px">862
uint32 ip = addr.sin_addr.s_addr;<BR>863
uint16 port = addr.sin_port;<BR>864
UdpSession *s = SessionHash::get(ip,
port);<BR>865<BR>866 if (!s)
{<BR>867 uint16 cmd
=
in.header.cmd;<BR>868
if (cmd == UDP_NEW_UIN || cmd == UDP_LOGIN)
{<BR>869
s = new UdpSession(in, ip,
port);<BR>870<BR>871
// Add it to the
hash<BR>872
SessionHash::put(s, ip,
port);<BR>873
keepAliveList.add(&s->listItem);<BR>874
} else<BR>875 s =
SessionHash::get(in.header.uin);<BR>876
}<BR>877 if
(s)<BR>878
s->onPacketReceived(in);<BR>879<BR>880
return true;<BR>}</P>
<P
style="MARGIN-BOTTOM: 0px; MARGIN-TOP: 0px">862和863把客户端的ip和port取出来,看864根据UdpSession的成员变量的队列ipportItem中找出ip、port相同的然后返回一个UdpSession</P>
<P
style="MARGIN-BOTTOM: 0px; MARGIN-TOP: 0px">866-876如果队列中没有的话,并且是新建Id或是登录就新创建一个UdpSession然后用ipportItem将它链入bucket队列中,然后用listItem</P>
<P
style="MARGIN-BOTTOM: 0px; MARGIN-TOP: 0px">链入keepAliveList队列。再调用onPacketReceived,这个函数是一个swith和case用来处理各种命令的跳转函数对于UPD_NEW_UIN的话就是onNewUIN(in);看onNewUIN</P>
<P
style="MARGIN-BOTTOM: 0px; MARGIN-TOP: 0px">handlePacket()->UdpSession::onReceive()->UdpSession::onNewUIN</P>
<P style="MARGIN-BOTTOM: 0px; MARGIN-TOP: 0px">void
UdpSession::onNewUIN(UdpInPacket
&in)<BR>{<BR>1314 if (_ops.enableRegister)
{<BR>1315 ICQ_STR
passwd;<BR>1316 in
>> passwd;<BR><A
name=request_callback></A><BR>1317
DBRequest *req = new DBRequest(DBF_UPDATE | DBF_INSERT, newUserCB,
this,
in.header.seq);<BR>1318
WRITE_STR(req, "INSERT INTO basic_tbl (passwd, msg_id) SELECT
PASSWORD(");<BR>1319 *req
<< passwd;<BR>1320
WRITE_STR(req, "), MAX(id) FROM
bcmsg_tbl");<BR>1321
DBManager::query(req);<BR>1322 } else
{<BR>1323 UdpOutPacket
*out = createPacket(UDP_NEW_UIN,
in.header.seq);<BR>1324
*out << (uint32)
0;<BR>1325
sendPacket(out);<BR>1326
}<BR>1327 isDead = 1;<BR>}</P>
<P
style="MARGIN-BOTTOM: 0px; MARGIN-TOP: 0px">如果现在启用了注册的话就将in中的密码赋给passwd,1317行新建一个DBRequest对象</P>
<P
style="MARGIN-BOTTOM: 0px; MARGIN-TOP: 0px">DBRequest::DBRequest(uint8
f, DB_CALLBACK cb, RefObject *obj, uint32
d)<BR>{<BR> flags = f;<BR>
callback = cb;<BR> refObj =
obj;<BR> data = d;<BR> res =
NULL;<BR> cursor = sql;<BR>}</P>
<P
style="MARGIN-BOTTOM: 0px; MARGIN-TOP: 0px">注意:将sql的地址赋给了cursor.1318如下:</P>
<P style="MARGIN-BOTTOM: 0px; MARGIN-TOP: 0px">#define
WRITE_STR(req, str) req->writeString(str, sizeof(str) - 1)</P>
<P style="MARGIN-BOTTOM: 0px; MARGIN-TOP: 0px">void
writeString(const char *text, int n) </P>
<P
style="MARGIN-BOTTOM: 0px; MARGIN-TOP: 0px">{<BR>
if (cursor - sql + n <= MAX_SQL) </P>
<P style="MARGIN-BOTTOM: 0px; MARGIN-TOP: 0px">
{<BR> memcpy(cursor, text,
n);<BR> cursor +=
n;<BR> }<BR>}</P>
<P
style="MARGIN-BOTTOM: 0px; MARGIN-TOP: 0px">1318-1320构成的SQL语句如下:</P>
<P style="MARGIN-BOTTOM: 0px; MARGIN-TOP: 0px">INSERT INTO basic_tbl
(passwd, msg_id) SELECT PASSWORD("你的密码"),MAX(id) FROM bcmsg_tbl;</P>
<P style="MARGIN-BOTTOM: 0px; MARGIN-TOP: 0px">然后到1321:</P>
<P
style="MARGIN-BOTTOM: 0px; MARGIN-TOP: 0px">handlePacket()->UdpSession::onReceive()->UdpSession::onNewUIN->DBManager::query</P>
<P style="MARGIN-BOTTOM: 0px; MARGIN-TOP: 0px">void
DBManager::query(DBRequest *req)<BR>{<BR> if
(req->callback &&
req->refObj)<BR>
req->refObj->addRef();<BR> Queue &q =
((req->flags & DBF_UPDATE) ? updateQueue :
queryQueue);<BR>
q.p
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -