您的位置:首页 > 理论基础 > 计算机网络

第二人生的源码分析(二十六)底层网络协议

2008-03-20 21:59 483 查看
为了理解第二人生的客户端与服务器的沟通,那么下面就来分析一下第二人生采用的网络协议。在目前的网络里,主要有两个协议:TCP和UDP,而第二人生里是采用UDP协议。TCP协议与UDP协议的主要区别,就是TCP有流量控制,可靠性控制,IP层组包功能,连接需要三次握手,而UDP没有这些保证,因此UDP发送的数据包需要自己来管理数据的有序性和可靠性。先来分析最底层的协议,它调用UDP发送数据的源码如下:
#001 // Returns TRUE on success.
#002 BOOL send_packet(int hSocket, const char *sendBuffer, int size, U32 recipient, int nPort)
#003 {
#004 // Sends a packet to the address set in initNet
#005 //
#006 int nRet = 0;
#007 U32 last_error = 0;
#008
#009 stDstAddr.sin_addr.s_addr = recipient;
#010 stDstAddr.sin_port = htons(nPort);
#011 do
#012 {
#013 nRet = sendto(hSocket, sendBuffer, size, 0, (struct sockaddr*)&stDstAddr, sizeof(stDstAddr));
#014
#015
#016 if (nRet == SOCKET_ERROR )
#017 {
#018 last_error = WSAGetLastError();
#019 if (last_error != WSAEWOULDBLOCK)
#020 {
#021 // WSAECONNRESET - I think this is caused by an ICMP "connection refused"
#022 // message being sent back from a Linux box... I'm not finding helpful
#023 // documentation or web pages on this. The question is whether the packet
#024 // actually got sent or not. Based on the structure of this code, I would
#025 // assume it is. JNC 2002.01.18
#026 if (WSAECONNRESET == WSAGetLastError())
#027 {
#028 return TRUE;
#029 }
#030 llinfos << "sendto() failed to " << u32_to_ip_string(recipient) << ":" << nPort
#031 << ", Error " << last_error << llendl;
#032 }
#033 }
#034 } while ( (nRet == SOCKET_ERROR)
#035 &&(last_error == WSAEWOULDBLOCK));
#036
#037 return (nRet != SOCKET_ERROR);
#038 }

在13行里调用WINDOWS API函数sendto来发送数据sendBuffer到目标地址stDstAddr里,这样就可以把数据交给WINDOWS的网络去发送数据了。由于这里采用异步的UDP来发送数据,因此采用了一个do while来处理正在阻塞的情况。当发送不成功,并且错误码是WSAEWOULDBLOCK,说明WINDOWS API正在发送过程中,不能接收数据,这样就循环地检查,直到发送成功,或者出错为止。第二人生里跟服务器发送的消息,就是这样发送出去的,看起来比较简单吧。



蔡军生 2008/3/20 QQ:9073204 深圳
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: