mxway的专栏

转载请注明出处:

本文是在飞鸽传书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){WSADATAwsaData;if (::WSAStartup(0x0101, &wsaData) != 0)returnGetSockErrorMsg("WSAStart()"), FALSE;if ((udp_sd = ::socket(AF_INET, SOCK_DGRAM, 0)) == INVALID_SOCKET)returnGetSockErrorMsg("Please setup TCP/IP(controlpanel->network)\r\n"), FALSE;if (recv_flg != TRUE)returnTRUE;if ((tcp_sd = ::socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET)returnGetSockErrorMsg("Please setup2 TCP/IP(controlpanel->network)\r\n"), FALSE;struct sockaddr_inaddr;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)returnGetSockErrorMsg("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");}BOOLflg = TRUE;// Non Blockif (::ioctlsocket(udp_sd, FIONBIO, (unsigned long *)&flg) != 0)returnGetSockErrorMsg("ioctlsocket(nonblock)"), FALSE;if (IsAvailableTCP() && ::ioctlsocket(tcp_sd, FIONBIO, (unsigned long *)&flg) != 0)returnGetSockErrorMsg("ioctlsocket tcp(nonblock)"), FALSE;flg = TRUE;// allow broadcastif (::setsockopt(udp_sd, SOL_SOCKET, SO_BROADCAST, (char *)&flg, sizeof(flg)) != 0)returnGetSockErrorMsg("setsockopt(broadcast)"), FALSE;intbuf_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)returnFALSE;returnTRUE;}

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

void TMsgApp::InitWindow(void){…intport_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_PORT0x0979

飞鸽传书默认服务的端口是十六进制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)returnFALSE;if (::WSAAsyncSelect(tcp_sd, hWnd, WM_TCPEVENT, FD_ACCEPT|FD_CLOSE) == SOCKET_ERROR)returnFALSE;returnTRUE;}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);returnTRUE;…}三、用户上线通知

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

只知道心痛得滴血,都只为你。

mxway的专栏

相关文章:

你感兴趣的文章:

标签云: