UDP的客户端看起来几乎就是服务器端的翻版,甚至比服务器端更简单——因为不需要bind()本机地址:

C++代码
  1. class UDPClientSock: public BaseSock {  
  2. protected:  
  3.     mutable sockaddr_in lastfromSockAddr;  
  4.     sockaddr_in destinationSockAddr;  
  5.     char* preBuffer;  
  6.     int preBufferSize;  
  7.     mutable int preReceivedLength;  
  8. public:  
  9.     explicit UDPClientSock(int pre_buffer_size = 32);  
  10.     virtual ~UDPClientSock();  
  11.     void UDPSetDest(const char* dest_IP,  
  12.             const unsigned short& dest_port);  
  13.     void UDPSetDest(const sockaddr_in& dest_sock_addr);  
  14.     int UDPReceive() const;  
  15.     int UDPSendtoDest(const char* send_data,  
  16.             const int& data_length) const;  
  17. };  

       在最初设计这个类的时候,我曾经考虑过安排一个服务器地址的私有数据成员,并且在构造函数里面指定服务器的地址。但是,后来我觉得使用“目的地”比“服务器”更加能体现出UDP无连接的本质特点。TCP之所以有个服务器,是因为TCP的客户端只能和自己的服务器端通讯。而UDP的客户端可以与任何一个UDP端口通讯——只要知道对方的地址(IP地址和UDP端口)就可以发送数据包。况且,在网络情况越来越复杂的今天,很多服务器都不仅仅使用一个IP地址或者域名,比如网站和游戏服务器,而对于客户端来说,只是在意连接到了指定的网站,比如google,而并不清楚是连接到google的哪个服务器。程序内部可能会根据网络条件对具体连接的服务器地址进行调整,所以,可以随时根据具体情况指定“目的地”,而不是一开始就指定一个“服务器”地址,这种策略显得更加灵活。

       通常情况下,客户端也并不在意lastfromSockAddr,因为最后一次来向的地址,往往就是目的地服务器的地址。我们说过,服务器的端口是指定的,这是为了让客户端明确的知道,可以去连接。而客户端的端口的端口则是系统指定的——我们并没有在客户端调用bind(),所以socket机制会自动帮我们绑定一个端口。通常客户端自己也不需要知道这个端口号是多少,只有接收到这次UDP数据报的服务器端知道,并且按照这个端口号将服务器的信息传送过来——没有收到这个端口发出的数据报的UDP端口很难知道这个系统指定的端口号是多少。但是,因为这个UDP端口实际上是可以接受来自其他任何UDP端口的数据的,所以,如果你需要验证发送某次数据的地址是不是你所期望的,比如是不是来自服务器,可能就会用到lastfromSockAddr。

C++代码
  1. UDPClientSock::UDPClientSock(int pre_buffer_size):  
  2. preBufferSize(pre_buffer_size), preReceivedLength(0)  
  3. {  
  4.     preBuffer = new char[preBufferSize];  
  5.     memset(&lastfromSockAddr, 0, sizeof(lastfromSockAddr));  
  6.     memset(&destinationSockAddr, 0, sizeof(destinationSockAddr));  
  7.   
  8.     sockFD = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);  
  9.     if (sockFD < 0) {  
  10.         sockClass::error_info("sock() failed.");  
  11.     }  
  12. }  
  13.   
  14. UDPClientSock::~UDPClientSock()  
  15. {  
  16.     delete [] preBuffer;  
  17.     close(sockFD);  
  18. }  

       其它4个类方法,跟server端的简直一模一样。

C++代码
  1. void UDPClientSock::UDPSetDest(const char* dest_IP,  
  2.                                const unsigned short& dest_port)  
  3. {  
  4.     destinationSockAddr.sin_family = AF_INET;  
  5.     destinationSockAddr.sin_addr.s_addr = inet_addr(dest_IP);  
  6.     destinationSockAddr.sin_port = htons(dest_port);  
  7. }  
  8.   
  9. void UDPClientSock::UDPSetDest(const sockaddr_in& dest_sock_addr)  
  10. {  
  11.     destinationSockAddr.sin_family = dest_sock_addr.sin_family;  
  12.     destinationSockAddr.sin_addr.s_addr = dest_sock_addr.sin_addr.s_addr;  
  13.     destinationSockAddr.sin_port = dest_sock_addr.sin_port;  
  14. }  
  15.   
  16. int UDPClientSock::UDPReceive() const  
  17. {  
  18.     socklen_t from_add_len = sizeof(lastfromSockAddr); //use int in win32  
  19.     preReceivedLength = recvfrom(    sockFD,  
  20.                                     preBuffer,  
  21.                                     preBufferSize,  
  22.                                     0,  
  23.                                     (sockaddr*)&lastfromSockAddr,  
  24.                                     &from_add_len);  
  25.     if ( preReceivedLength < 0) {  
  26.         sockClass::error_info("recv() failed.");  
  27.     }  
  28.   
  29.     return preReceivedLength;  
  30. }  
  31.   
  32. int UDPClientSock::UDPSendtoDest(const char* send_data,  
  33.                                  const int& data_length) const  
  34. {  
  35.     int send_message_size = sendto(    sockFD,  
  36.                                     send_data,  
  37.                                     data_length,  
  38.                                     0,  
  39.                                     (sockaddr*)&destinationSockAddr,  
  40.                                     sizeof(destinationSockAddr));  
  41.     if (send_message_size < 0) {  
  42.         sockClass::error_info("send() failed.");  
  43.     }  
  44.     if (send_message_size != data_length) {  
  45.         sockClass::error_info(  
  46.             "send() sent a different number of bytes than expected.");  
  47.     }  
  48.     return send_message_size;  
  49. }  
除非特别注明,鸡啄米文章均为原创
转载请标明本文地址:http://www.rbu.tw/software/464.html
2015年11月17日
作者:鸡啄米 分类:软件开发 浏览: 评论:0