用下面的语句: rc=WSAAsyncSelect(s,hWnd,wMsg,FD-READ FD-WRITE); 当套接字s上被提名的一个网络事件发生时,窗口hWnd将收到消息wMsg,变量lParam的低字指示网络发生的事件,高字指示错误码。应用程序就可以通过这些信息来决定自己的下一步动作。 三、网络实时通信的实现 我们来设计一个简单的基于连接的点对点网络实时通信程序。服务器首先启动,它建立套接字之后等待客户机的连接;客户机在启动后,建立套接字,然后和服务器建立连接;连接建立后,客户机通过连接给服务器发送一段数据,服务器接收后又将它发送回来,客户机再发送,如此循环,直至用户命令客户机退出或网络出错;客户机关闭连接和套接字后退出,服务器在检测到连接关闭后,关闭套接字自动结束。 我们的实例是UNIX下基于BSD Socket的服务器程序和Windows下基于WINSOCK的客户机程序之间的通信。服务器在主机UNIX下直接运行,前台和后台均可;客户机在Windows下运行,带一个参数,即主机的名字。如win client rs6000,rs6000是在HOSTS文件中已定义好的主机名。 我们先看客户机程序,首先定义几个宏、菜单资源和部分全局变量。 程序1:部分Windows程序源代码(宏、菜单和变量) #define USERPORT 3333/*用户定义端口号*/ #define IDM-START101/*“启动”菜单项标志*/ #define IDM-EXIT102/*“退出”菜单项标志*/ #define UM-SOCKWM-USER+0x100/*用户定义网络消息*/ ClientMenu MENU/*客户机菜单*/ BEGIN POPUP &Server BEGIN MENUITEM &Start..., IDM-START MENUITEM &Stop,IDM-STOP END END #include /*必须包含winsock.h头文件*/ HANDLEhInst; charserver-address = {0};/*服务器地址缓冲区*/ charbuffer;/*接收发送缓冲区*/ char FAR *lpBuffer=&buffer; SOCKETs=0;/*套接字*/ struct sockaddr-in dst-addr;/*目标地址*/ struct hostent *hostaddr;/*主机地址*/ struct hostent hostnm; intcount=0;/*发送接收循环计数器*/ 客户机程序的窗口主函数很简单,它在注册窗口类、建立窗口后,只是给主窗口函数发送一个用户消息,然后就进入Windows消息处理循环。 程序2:部分Windows程序源代码(窗口主函数) int PASCAL WinMain(HANDLE hInstance, HANDLE hPrevInstance, LPSTR lp CmdL ine, int nCmdShow) { HWND hWnd; MSGmsg; lstrcpy((LPSTR) server-address, lpCmdLine);/*取主机名字*/ if (!hPrevInstance) if (!InitApplication(hInstance)) return (FALSE); hInst=hInstance; hWnd=CreateWindow(ClientClass,Windows ECHO Client, WS-OVERLAPPEDWINDOW,CW-USEDEFAULT,CW-USEDEFAULT, CW-USEDEFAULT,CW-USEDEFAULT, NULL,NULL,hInstance,NULL); if (!hWnd) return (FALSE); ShowWindow(hWnd,nCmdShow); UpdateWindow(hWnd); /*给主窗口函数发送WM-USER消息*/ PostMessage(hWnd,WM-USER,(WPARAM) 0,(LPARAM) 0); while (GetMessage(&msg,NULL,NULL,NULL)) { TranslateMessage(&msg); DispatchMessage(&msg); } return (msg.wParam); } 主窗口函数ClientProc是程序的主要部分,它处理相关的消息:在接到消息WM-USER后,它调用函数WSAStartup()初始化Windows Sockets DLL,并检查其版本号,然后通过主机名获取主机地址;在接到消息WM-COMMAND时,如果是命令IDM-START,则调用子程序Client()建立套接字,并试图和服务器建立连接,如果是命令IDM-STOP,则调用函数WSACleanup()终止Windows Sockets DLL,并发出终止应用程序的消息;在接到消息UM-SOCK时,它根据参数lParam指示的网络事件,进行相应的操作,然后选择下一个期望的网络事件。 程序3:部分Windows程序源代码(主窗口函数) long FAR PASCAL ClientProc(HWND hWnd, unsigned message, UINT wParam, LONG lParam) { int length,i; WSADATAwsaData;/*描述Windows Sockets实现细节的数据结构*/ intStatus; switch (message) { case WM-USER: Status=WSAStartup(0x101,&wsaData); if (Status !=0) { AlertUser(hWnd,WSAStartup() failed); PostQuitMessage(0); } if (LOBYTE(wsaData.wVersion) !=1 HIBYTE(wsaData.wVersion) !=1) { /*现在支持的版本是WINSOCK.DLL 1.1*/ AlertUser(hWnd, WSAStartup() Version not match); WSACleanup(); PostQuitMessage(0); } hostaddr=gethostbyname(server-address); if (hostaddr==NULL) { AlertUser(hWnd, gethostbyname ERROR ); WSACleanup (); PostQuitMessage(0); } memcpy(&hostnm,hostaddr,sizeof(struct hostent)); break; case WM-COMMAND: switch (wParam) { case IDM-START: if (!Client(hWnd)) { closesocket(s); AlertUser(hWnd, Start Failed); } break; case IDM-STOP: WSACleanup(); PostQuitMessage(0); break; } break; case UM-SOCK: switch (lParam) { case FD-CONNECT:/*网络事件:连接建立*/ if (!set-select(hWnd, FD-WRITE))/*选择:期望发送*/ closesocket(s); break; case FD-READ:/*网络事件:读准备好*/ if (!receive-pkt(hWnd)) {/*接收数据*/ AlertUser(hWnd, Receive Packet Failed); closesocket(s); break; } if (!set-select(hWnd, FD-WRITE))/*选择:期望发送*/ closesocket(s); br 上一页 [1] [2] [3] 下一页
Tags:
|