转载请注明出处:http://blog.csdn.net/mxway/article/details/44195099

本文是在飞鸽传书2.06源码基础之上进行分析的。

一、网络的初始化

飞鸽传书主窗口对应的类TMainWin的构造函数中有如下的代码

cfg = new Cfg(nicAddr, portNo = _portNo);if ((msgMng = new MsgMng(nicAddr, portNo, cfg))->GetStatus() == FALSE){::ExitProcess(0xffffffff);return;}

在MsgMng类的构造函数中调用WSockInit。

MsgMng::MsgMng(ULONG nicAddr, int portNo, Cfg *_cfg)
{...local.addr = nicAddr;local.portNo = htons(portNo);...if (WSockInit(cfg ? TRUE : FALSE) == FALSE)return;...
}
BOOL MsgMng::WSockInit(BOOL recv_flg)
{WSADATA        wsaData;if (::WSAStartup(0x0101, &wsaData) != 0)return GetSockErrorMsg("WSAStart()"), FALSE;if ((udp_sd = ::socket(AF_INET, SOCK_DGRAM, 0)) == INVALID_SOCKET)return  GetSockErrorMsg("Please setup TCP/IP(controlpanel->network)\r\n"), FALSE;if (recv_flg != TRUE)return  TRUE;if ((tcp_sd = ::socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET)return   GetSockErrorMsg("Please setup2 TCP/IP(controlpanel->network)\r\n"), FALSE;struct sockaddr_in   addr;memset(&addr, 0, sizeof(addr));addr.sin_family         = AF_INET;addr.sin_addr.s_addr = local.addr;addr.sin_port         = local.portNo;if (::bind(udp_sd, (LPSOCKADDR)&addr, sizeof(addr)) != 0)return    GetSockErrorMsg("bind()"), FALSE;if (::bind(tcp_sd, (LPSOCKADDR)&addr, sizeof(addr)) != 0){::closesocket(tcp_sd);tcp_sd = INVALID_SOCKET;GetSockErrorMsg("bind(tcp) error. Can't support file attach");}BOOL flg = TRUE;    // Non Blockif (::ioctlsocket(udp_sd, FIONBIO, (unsigned long *)&flg) != 0)return  GetSockErrorMsg("ioctlsocket(nonblock)"), FALSE;if (IsAvailableTCP() && ::ioctlsocket(tcp_sd, FIONBIO, (unsigned long *)&flg) != 0)return    GetSockErrorMsg("ioctlsocket tcp(nonblock)"), FALSE;flg = TRUE;          // allow broadcastif (::setsockopt(udp_sd, SOL_SOCKET, SO_BROADCAST, (char *)&flg, sizeof(flg)) != 0)return    GetSockErrorMsg("setsockopt(broadcast)"), FALSE;int   buf_size = MAX_SOCKBUF, buf_minsize = MAX_SOCKBUF / 2;        // UDP if (::setsockopt(udp_sd, SOL_SOCKET, SO_SNDBUF, (char *)&buf_size, sizeof(int)) != 0&&  ::setsockopt(udp_sd, SOL_SOCKET, SO_SNDBUF, (char *)&buf_minsize, sizeof(int)) != 0)GetSockErrorMsg("setsockopt(sendbuf)");buf_size = MAX_SOCKBUF, buf_minsize = MAX_SOCKBUF / 2;if (::setsockopt(udp_sd, SOL_SOCKET, SO_RCVBUF, (char *)&buf_size, sizeof(int)) != 0&&   ::setsockopt(udp_sd, SOL_SOCKET, SO_RCVBUF, (char *)&buf_minsize, sizeof(int)) != 0)GetSockErrorMsg("setsockopt(recvbuf)");flg = TRUE;  // REUSE ADDRif (IsAvailableTCP() && ::setsockopt(tcp_sd, SOL_SOCKET, SO_REUSEADDR, (char *)&flg, sizeof(flg)) != 0)GetSockErrorMsg("setsockopt tcp(reuseaddr)");if (IsAvailableTCP() && ::listen(tcp_sd, 5) != 0)return    FALSE;return    TRUE;
}

在WSockInit中初始化进行网络编程所要用的dll,并设置了tcp服务及udp所占用的端口号,并设置udp及tcp的socket为非阻塞模式。tcp及udp服务所占的端口是由TMainWin的构造函数传到MsgMng的构造函数中的。在TMainWin的构造函数传给MsgMng的端号来自TMainWin的构造函数。回到Ipmsg.cpp的TMsgApp::InitWindow函数中(具体可参考前面的飞鸽传书源码分析文章)

void TMsgApp::InitWindow(void)
{...int         port_no = atoi(cmdLine);if (port_no == 0)port_no = IPMSG_DEFAULT_PORT;...mainWnd = new TMainWin(nicAddr, port_no);mainWnd->Create(class_name, IP_MSG, WS_OVERLAPPEDWINDOW | (IsNewShell() ? WS_MINIMIZE : 0));...}

在InitWindow函数可以看到所使用端口的初始化,cmdLine是指以命令行方式运行飞鸽传书时参的端口参数,为了简化问题不考虑命令运行。port_no被初始化为IPMSG_DEFAULT_PORT,IPMSG_DEFAULT_PORT是一个宏定义

#define IPMSG_DEFAULT_PORT 0x0979

飞鸽传书默认服务的端口是十六进制979也就是十进制的2425。

二、网络非阻塞模式

在windows下实现socket有多种方式,飞鸽传书使用的是将网络事件以消息方式发送给窗口句柄,而处理网络事件的窗口就是TMainWin。在IPmsg.cpp的InitWindow调用完mainWnd->Create(class_name, IP_MSG, WS_OVERLAPPEDWINDOW | (IsNewShell() ? WS_MINIMIZE : 0));后会执行TMainWin的EvCreate(调用过程详解见第二篇的消息机制)

BOOL TMainWin::EvCreate(LPARAM lParam)
{...msgMng->AsyncSelectRegist(hWnd);...if (msgMng->GetStatus())EntryHost();
}
BOOL MsgMng::AsyncSelectRegist(HWND hWnd)
{if (hAsyncWnd == 0)hAsyncWnd = hWnd;if (::WSAAsyncSelect(udp_sd, hWnd, WM_UDPEVENT, FD_READ) == SOCKET_ERROR)return   FALSE;if (::WSAAsyncSelect(tcp_sd, hWnd, WM_TCPEVENT, FD_ACCEPT|FD_CLOSE) == SOCKET_ERROR)return  FALSE;return    TRUE;
}

WSAAsyncSelect(udp_sd,hWnd, WM_UDPEVENT,FD_READ),当对udp_sd进行发送数据时,将交由TMainWin的消息处理机制进行处理。由于WM_UDPEVENT是飞鸽传书程序自定义的消息机制所以由TMainWin的EventUser进行处理(具体参照第二篇飞鸽传书的消息机制)。

BOOL TMainWin::EventUser(UINT uMsg, WPARAM wParam, LPARAM lParam)
{...case WM_UDPEVENT:UdpEvent(lParam);return    TRUE;...
}

三、用户上线通知

飞鸽传书是工作是局域网的程序,当有新的设备使用飞鸽传书程序时,会自动通知到其它已经在线的用户,将自己显示到其它用户的列表中。

调用完msgMng->AsyncSelectRegist(hWnd);将网络事件与窗口句柄勾搭上之后,程序就会对局域网进行广播,告诉其它人自己打开了飞鸽传书程序。

void TMainWin::EntryHost(void)
{...BroadcastEntry(IPMSG_BR_ENTRY);...
}
void TMainWin::BroadcastEntry(ULONG mode)
{msgMng->Send((ULONG)~0, htons(portNo), host_status, GetNickNameEx(), cfg->GroupNameStr);
}

msgMng->Send((ULONG)~0, htons(portNo), host_status, GetNickNameEx(), cfg->GroupNameStr);向局域网发送广播消息,告诉别人自己上线。其它正在运行的程序收到这个消息后就将收到的信息存储起来,以备后面使用,具体过程不再详解。关于飞鸽传书发送消息的格式后面的文章再介绍。

飞鸽传书源码分析三-网络相关推荐

  1. 飞鸽传书源码分析-程序启动过程

    本文章是在飞鸽传书的2.06源码基础上分析 飞鸽传书源码运行流程如下,本篇文章只说明了飞鸽传书的启动过程,对于飞鸽伟书的消息机制及菜单加载等功能都不在本篇文章范围之内. 1. WinMain函数 [c ...

  2. 表示深深的感谢飞鸽传书源码

    摘要:飞鸽传书源码 2012年07月13日最后找到旅馆订房资料,才紧急联络上当事人,就有机会获得抢鲜体验星辰变游戏的资格和游戏下次测试线上礼包等,如果一定要在公司上网,不止一次的表示希望游戏尽快推出, ...

  3. android版本飞鸽传书源码

    2019独角兽企业重金招聘Python工程师标准>>> 说明 第一次在eoe论坛发帖.去年11月份开始自学android开发, 长期混迹在eoe里潜水.今天来点贡献.贡献出我自己写的 ...

  4. 东风来了的飞鸽传书源码

    摘要:飞鸽传书源码 2012年07月13日浏览器支持IE,刁杨与小孽双双扮靓你的桌面,Mac等,由内地版瑶瑶刁杨,让她们与你日夜相伴,想要,对飞鸽传书2007访客而言,不能养宠物,最震撼的独家特权大礼 ...

  5. Linux飞鸽传书源码,Ubuntu 7.10下源码安装飞鸽传书IpMsg

    IPMsg 是一款局域网内即时通信软件, 基于 TCP/IP(UDP),可运行于多种操作平台(Win/Mac/UNIX/Java), 并实现跨平台信息交流. 不需要服务器支持,支持文件/文件夹的传送, ...

  6. Linux飞鸽传书源码,图解Ubuntu下编译安装飞鸽传书IPMsg步骤

    因为IPMsg官方网站发布的Unix/Linux版本都是源代码包,需要在Ubuntu中编译,因此,需要在本机安装开发环境. 我下载的g2ipmsg-0.9.5.tar,下载地址见http://www. ...

  7. Linux飞鸽传书源码,Linux下的飞鸽传书

    202.106.74.* 于 2007-07-25 17:25:33发表: [root@DevHost g2ipmsg-0.8.6]# make make all-recursive make[1]: ...

  8. 【投屏】Scrcpy源码分析三(Client篇-投屏阶段)

    Scrcpy源码分析系列 [投屏]Scrcpy源码分析一(编译篇) [投屏]Scrcpy源码分析二(Client篇-连接阶段) [投屏]Scrcpy源码分析三(Client篇-投屏阶段) [投屏]Sc ...

  9. Nouveau源码分析(三):NVIDIA设备初始化之nouveau_drm_probe

    Nouveau源码分析(三) 向DRM注册了Nouveau驱动之后,内核中的PCI模块就会扫描所有没有对应驱动的设备,然后和nouveau_drm_pci_table对照. 对于匹配的设备,PCI模块 ...

最新文章

  1. python培训班 北京-北京python培训班哪家好
  2. 通过Serverless技术降低微服务应用资源成本
  3. c语言中用文件处理数据,C语言文件处理 -C语言从文件中读写格式化数据
  4. MFC中实现的画箭头算法 (Arrow in MFC)
  5. javascript一次性更换访问统计代码
  6. ORACLE基本配置
  7. 关于Spring MVC中文乱码问题的解决方法
  8. php单图上传并预览,JavaScript实现单图片上传并预览功能
  9. int输出%f浮点值是0,double/float 浮点数%d输出0的原因
  10. 奇怪的Residential Gateway Device设备
  11. 使用Mapnik生成地形图——thematicmapping.org译文(四)
  12. 线性表的基本操作Basic operation of SequenceList
  13. 坐标计算距离公式 火星坐标系_根据经纬度计算距离的公式、百度坐标转换成GPS坐标(PHP版)...
  14. 苹果7手机html5测试,测试开发之前端——No7.HTML5中的鼠标事件
  15. [经典收藏]1200个Photoshop经典实例打造ps高手!
  16. 利用Wifidog实现微信wifi连接以及自写认证服务器
  17. 原生小程序使用 flyio,以及拦截器
  18. FTP下载 550 Failed to open file
  19. 凯撒加密的最简单的理解与实现(Java版)
  20. YzmCMS系统精仿系统下载站模板 精品系统软件整站下载站

热门文章

  1. 【Python 3】SyntaxError: (unicode error) 'utf-8' codec can't decode byte 0xcf in position 0
  2. UC伯克利提出小批量MH测试:令MCMC方法在自编码器中更强劲
  3. vb.net 教程 3-4 窗体编程 公共控件8 RichTextBox
  4. Unity实现模型显示在UI前面
  5. SONY索尼微单a6300/a7相机提示需要修复视频打不开,如何修复MP4视频?
  6. 服务器里面为什么有的信号好低,为什么同一个地方手机信号却不同?带你揭开手机信号的神秘面纱...
  7. 1993年考研数学一真题pdf
  8. python(opencv + pyaudio + moviepy)实现录制音视频文件并合并
  9. 用C++写一个日历程序,要求输入年份,显示全年的日历
  10. MEF学习(一) ----- MEF介绍