IpMsg代码分析(三)

本次主要分析通信部分:

Msgmng.cpp为通信处理部分的源文件,其中包括了几乎所有的socket通信代码。

Class Msgmng为通信的管理类。构造函数如下:

Line: 18

MsgMng::MsgMng(ULONG nicAddr, int portNo, Cfg *_cfg){}

此函数主要功能如下:

1、对数据成员进行初始化赋值;

2、调用WSockInit函数初始化sock,此初始化函数在下面分析。此函数设置了socket的属性,比较重要。

3、获取主机名称、获取当前用户名,并且填充信息结构。

BOOL MsgMng::WSockInit(BOOL recv_flg)

函数为初始化文件。其中实现的主要功能如下:

 

 

  1. //Line:67
  2. if ((udp_sd = ::socket(AF_INET, SOCK_DGRAM, 0)) == INVALID_SOCKET)
  3.     return  GetSockErrorMsg("Please setup TCP/IP(controlpanel->network)/r/n"),FALSE;

//创建基于数据报的socket udp_sd;

 

 

  1. if ((tcp_sd = ::socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET)
  2. return  GetSockErrorMsg("Please setup2 TCP/IP(controlpanel->network)/r/n"), FALSE;
  3. //创建基于流的 socket tcp_sd;

创建本地地址结构,本地地址和本地端口均保存在local中,local为自己定义的一个HostSub类型的数据,HostSub类型的数据保存用户名称,主机名称、主机端口、主机地址等信息。

  1. //Line: 76
  2. struct sockaddr_in  addr;
  3. memset(&addr, 0, sizeof(addr));
  4. addr.sin_family         = AF_INET;
  5. addr.sin_addr.s_addr    = local.addr;
  6. addr.sin_port           = local.portNo;

 

  1. //Line:82
  2. if (::bind(udp_sd, (LPSOCKADDR)&addr, sizeof(addr)) != 0)
  3.     return  GetSockErrorMsg("bind()"), FALSE;
  4. if (::bind(tcp_sd, (LPSOCKADDR)&addr, sizeof(addr)) != 0)
  5. {
  6.     ::closesocket(tcp_sd);
  7.     tcp_sd = INVALID_SOCKET;
  8.     GetSockErrorMsg("bind(tcp) error. Can't support file attach");
  9. }

分别绑定套接字和本机地址,由于是用的不同通信协议(udp、tcp),故相同的地址和端口可以绑定两次。

  1. //Line : 92
  2. BOOL    flg = TRUE;  //none block
  3. if (::ioctlsocket(udp_sd, FIONBIO, (unsigned long *)&flg) != 0)
  4. return  GetSockErrorMsg("ioctlsocket(nonblock)"), FALSE;
  5. if (IsAvailableTCP() && ::ioctlsocket(tcp_sd, FIONBIO, (unsigned long *)&flg) != 0)
  6. return  GetSockErrorMsg("ioctlsocket tcp(nonblock)"), FALSE;
  7. flg = TRUE;         // allow broadcast
  8. if (::setsockopt(udp_sd, SOL_SOCKET, SO_BROADCAST, (char *)&flg, sizeof(flg)) != 0)
  9. return  GetSockErrorMsg("setsockopt(broadcast)"), FALSE;
  10. //以上部分设置两个套接字的套接字选项,设置udp为非阻塞模式,tcp_sd允许发送广播信息。

 

  1. Line :103
  2. int buf_size = MAX_SOCKBUF, buf_minsize = MAX_SOCKBUF / 2;  
  3. if (::setsockopt(udp_sd, SOL_SOCKET, SO_SNDBUF, (char *)&buf_size, sizeof(int)) != 0
  4.     &&  ::setsockopt(udp_sd, SOL_SOCKET, SO_SNDBUF, (char *)&buf_minsize, sizeof(int)) != 0)
  5.     GetSockErrorMsg("setsockopt(sendbuf)");
  6. //SOCKET,SNDBUF用于设置 发送缓冲区的size
  7.  //Sets the per-socket buffer size for sending data
  1. //Line: 108
  2. buf_size = MAX_SOCKBUF, buf_minsize = MAX_SOCKBUF / 2;
  3. if (::setsockopt(udp_sd, SOL_SOCKET, SO_RCVBUF, (char *)&buf_size, sizeof(int)) != 0
  4.     &&  ::setsockopt(udp_sd, SOL_SOCKET, SO_RCVBUF, (char *)&buf_minsize, sizeof(int)) != 0)
  5. GetSockErrorMsg("setsockopt(recvbuf)");
  6. //同上,设置接受缓冲区的size
  1. //Line : 113
  2. flg = TRUE; // REUSE ADDR
  3. if (IsAvailableTCP() && ::setsockopt(tcp_sd, SOL_SOCKET, SO_REUSEADDR, (char *)&flg, sizeof(flg)) != 0)
  4. GetSockErrorMsg("setsockopt tcp(reuseaddr)");
  5. if (IsAvailableTCP() && ::listen(tcp_sd, 5) != 0)
  6.     return  FALSE;
  7. 设置地址重用,并且开始进行监听,看监听函数在这里。

以下函数为MsgMng的Send函数,函数有三个原型,分别如下:

参数2传递地址,参数2, 参数3传递将要传送的数值。在程序处理中,将int类型的数值转换成char型,调用重载函数2进行发送。

 

  1. 1)BOOL MsgMng::Send(HostSub *hostSub, ULONG command, int val)
  2. {
  3.     char    buf[MAX_NAMEBUF];
  4.     wsprintf(buf, "%d", val);
  5.     return  Send(hostSub->addr, hostSub->portNo, command, buf);
  6. }
  7. //函数2调用函数3进行发送。
  8. 2)BOOL MsgMng::Send(HostSub *hostSub, ULONG command, const char *message, const char *exMsg)
  9. {
  10.     return  Send(hostSub->addr, hostSub->portNo, command, message, exMsg);
  11. }
  12. //函数调用MakeMsg函数根据参数生成不同的消息类型,此消息类型为自己定义的,此编程思想值得借鉴。
  13. 3)BOOL MsgMng::Send(ULONG host, int port_no, ULONG command, const char *message, const char *exMsg)
  14. {
  15.     char    buf[MAX_UDPBUF];
  16.     int     trans_len;
  17.     
  18.     MakeMsg(buf, command, message, exMsg, &trans_len);
  19.     return  UdpSend(host, port_no, buf, trans_len);
  20. }

 

MakeMsg函数完成消息的组装。函数有两个重载版本,主要功能从函数2实现。

  1. 1)ULONG MakeMsg(char *udp_msg, ULONG command, const char *msg, const char *exMsg=NULL, int *packet_len=NULL) 
  2. {
  3.     return  MakeMsg(udp_msg, MakePacketNo(), command, msg, exMsg, packet_len); 
  4. }
  5. 函数一创建分包号,然后调用函数二。
  6. 2)ULONG MsgMng::MakeMsg(char *buf, int _packetNo, ULONG command, const char *msg, const char *exMsg, int *packet_len)
  7. {
  8.     int     len, ex_len = exMsg ? strlen(exMsg) + 1 : 0, max_len = MAX_UDPBUF;
  9.     if (packet_len == NULL)
  10.         packet_len = &len;
  11.     *packet_len = wsprintf(buf, "%d:%ld:%s:%s:%ld:", IPMSG_VERSION, _packetNo, local.userName, local.hostName, command);
  12.     if (ex_len + *packet_len + 1 >= MAX_UDPBUF)
  13.         ex_len = 0;
  14.     max_len -= ex_len;
  15.     if (msg != NULL)    // sprintf偼巊傢側偄
  16.                                 // 此处为指针后移,使当前buf指针指向前面已经编制好的消息(v、no、username、hostname)等信息的后面。!!!!localNettoUnix主要完成除去字符串中的换行字符的目的 'r'
  17.         *packet_len += LocalNewLineToUnix(msg, buf + *packet_len, max_len - *packet_len);
  18.     (*packet_len)++;
  19. // 将扩展信息添加到消息包中。
  20.     if (ex_len)
  21.     {
  22.         memcpy(buf + *packet_len, exMsg, ex_len);
  23.         *packet_len += ex_len;
  24.     }
  25.     
  26.     return  _packetNo;
  27. }

下面分析 udpsend函数,此函数完成主要的数据发送任务。

 

  1. 2)BOOL MsgMng::UdpSend(ULONG host_addr, int port_no, const char *buf, int len)
  2. {
  3.     struct sockaddr_in  addr;
  4.     
  5.     memset(&addr, 0, sizeof(addr));
  6.     addr.sin_family         = AF_INET;
  7.     addr.sin_port           = port_no;
  8.     addr.sin_addr.s_addr    = host_addr;
  9.     
  10.     if (::sendto(udp_sd, buf, len, 0, (LPSOCKADDR)&addr, sizeof(addr)) == SOCKET_ERROR)
  11.     {
  12.         switch (WSAGetLastError()) {
  13.         case WSAENETDOWN:
  14.             break;
  15.         case WSAEHOSTUNREACH:
  16.             static  BOOL    done;
  17.             if (done == FALSE) {
  18.                 done = TRUE;
  19.             }
  20.             return  FALSE;
  21.         default:
  22.             return  FALSE;
  23.         }
  24.         
  25. // 重置socket
  26.         if (WSockReset() != TRUE)
  27.             return  FALSE;
  28.         
  29. // 注册此窗口为异步选择窗口。在对socket消息的处理中应用了异步选择机制,使socket消息关联到特定的消息窗口。
  30.         if (hAsyncWnd && AsyncSelectRegist(hAsyncWnd) != TRUE)
  31.             return  FALSE;
  32. // 尝试重新发送       
  33.         if (::sendto(udp_sd, buf, len, 0, (LPSOCKADDR)&addr, sizeof(addr)) == SOCKET_ERROR)
  34.             return  FALSE;
  35.     }
  36.     
  37.     return  TRUE;
  38. }
  39. Line:172
  40. BOOL MsgMng::AsyncSelectRegist(HWND hWnd)
  41. {
  42.     if (hAsyncWnd == 0)
  43.         hAsyncWnd = hWnd;
  44.     
  45. // 用自定义的消息(特殊时间发生)通知特定的窗口处理socket消息
  46.     if (::WSAAsyncSelect(udp_sd, hWnd, WM_UDPEVENT, FD_READ) == SOCKET_ERROR)
  47.         return  FALSE;
  48.     
  49.     if (::WSAAsyncSelect(tcp_sd, hWnd, WM_TCPEVENT, FD_ACCEPT|FD_CLOSE) == SOCKET_ERROR)
  50.         return  FALSE;
  51.     
  52.     return  TRUE;
  53. }

未完待续...

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值