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

为了理解第二人生的客户端与服务器的沟通,那么下面就来分析一下第二人生采用的网络协议。在目前的网络里,主要有两个协议: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 深圳
 
posted @ 2008-03-20 21:59  ajuanabc  阅读(199)  评论(0编辑  收藏  举报