本站首页    管理页面    写新日志    退出


 

 

 


最新日志

练车
今天是2011年07月02号
温馨
CInternetSession 类
CHttpFile实现Get/Post
在MFC中加一个控制台DOS界面
strtol 函数
outputParam
有关CTime和ColeDateTime
variant_t ,_bstr_t 与

 


 

最近的评论

回复:CHttpFile实现Get/Po
回复:好久没有来了
回复:参数自整定的模糊PID
回复:电子设计大赛自由命题可参考的题目
回复:数字万用表使用方法
回复:公交车上巨搞笑的一幕
回复:电子设计大赛自由命题可参考的题目
回复:电子设计大赛自由命题可参考的题目
回复:电子设计大赛自由命题可参考的题目
回复:暑假回来

 


 

连接




    

Winsock I/O模型之WSAAsyncSelect
sccwqiang 发表于 2008-2-21 20:58:31

           Winsock I/O模型之WSAAsyncSelect   Winsock提供了一个很有用的异步I/O模型,利用这个模型,应用程序可以在一个套接字上接收以Windows消息为基础的网络事件通知。这个模型最开始出现在Winsock 1.1版本中,是为了帮助开发者面向一些早期的16位Windows平台而设计的。但是现在的应用程序仍然可以从这种模型中得到好处,就连MFC中的CSocket类也采纳了这种模型。 由于该模型是基于Windows消息机制的,所以要想使用这种模型必须要Create一个窗口,这个窗口将会被用来接收消息。接下来建立套接字,然后调用WSAAsyncSelect函数,打开窗口消息通知,函数原型如下: int WSAAsyncSelect(SOCKET s, HWND hWnd, unsigned int uMsg, long lEvent); 其中s就是我们想要的那个套接字;hWnd是接收消息通知那个窗口句柄;wMsg参数指定在发生网络事件时要接受的消息,通常设成比WM_USER大的一个值,以避免消息冲突;lEvent指定了一个位掩码,对应一系列网络事件的组合,见下表: Event 含义 FD_READ 程序想要接收有关是否可读的通知,以便读入数据 FD_WRITE 程序想要接收有关是否可写的通知,以便写入数据 FD_OOB 程序想要接收是否有OOB数据到达的通知 FD_ACCEPT 程序想要接收与进入连接有关的通知 FD_CONNECT 程序想要接收与一次连接或多点接入有关的通知 FD_CLOSE 程序想要接收与套接字关闭有关的通知 FD_QOS 程序想要接收套接字“服务质量(QoS)”发生变化的通知 FD_GROUP_QOS 暂时没用,属于保留事件 FD_ROUTING_INTERFACE_CHANGE 程序想要接收有关到指定地址的路由接口发生变化的通知 FD_ADDRESS_LIST_CHANGE 程序想要接收本地地址变化的通知 当程序在一个套接字上调用WSAAsyncSelect成功后,这个程序就会在与hWnd窗口句柄对应的窗口例程中以Windows消息的形式接收网络事件通知。窗口例程通常定义成这个样子: LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam,          LPARAM lParam)其中wParam参数指定在其上面发生了一个网络事件的套接字,如果定义了多个套接字,这个参数就显得很重要了。lParam参数则包含了两方面的重要信息,它的低位字指定了已经发生的网络事件,而高位字包含了可能出现的错误代码。 简单的来说,这个模型的具体使用流程就是:当网络消息抵达一个窗口例程后,程序要先检测lParam的高位字节,从而判断是否在套接字上面发生了网络错误。现成的宏已经有在这里了 --> WSAGETSELECTERROR,可以用它返回高字节包含的错误信息,如果没有发现任何的错误,接下来就是确定究竟是什么类型的网络事件触发了这条Windows消息,这个操作也有现成的宏 --> WSAGETSELECTEVENT 下面就是源代码,其中部分很基本的代码我就省略掉了,编译平台为Win2000 Server with SP2 + VC6.0 with SP5 #include <windows.h>#include <winsock2.h> #define PORT 5150#define DATA_BUFSIZE 8192 typedef struct _SOCKET_INFORMATION { BOOL RecvPosted; CHAR Buffer[DATA_BUFSIZE]; WSABUF DataBuf; SOCKET Socket; DWORD BytesSEND; DWORD BytesRECV; _SOCKET_INFORMATION *Next;} SOCKET_INFORMATION, * LPSOCKET_INFORMATION; #define WM_SOCKET (WM_USER + 1) void CreateSocketInformation(SOCKET s, HWND);LPSOCKET_INFORMATION GetSocketInformation(SOCKET s);void FreeSocketInformation(SOCKET s); LPSOCKET_INFORMATION SocketInfoList; LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ; int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,    LPSTR lpCmdLine, int nCmdShow){ DWORD Ret; SOCKET Listen; SOCKADDR_IN InternetAddr; WSADATA wsaData; static TCHAR szAppName[] = TEXT ("HelloWin") ; HWND hwnd ; MSG msg ; WNDCLASS wndclass ;  // Prepare echo server wndclass.style = CS_HREDRAW | CS_VREDRAW ; ... ... RegisterClass (&wndclass); hwnd = CreateWindow (...) ; // creation parameters ShowWindow (hwnd, nCmdShow) ; UpdateWindow (hwnd) ; if ((Ret = WSAStartup(0x0202, &wsaData)) != 0) {  MessageBox(hwnd, TEXT("Start socket failed"), TEXT("error"), MB_OK);  ExitProcess(1); } if ((Listen = socket (PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {  MessageBox(hwnd, TEXT("socket() failed"), TEXT("error"), MB_OK);  ExitProcess(1); } WSAAsyncSelect(Listen, hwnd, WM_SOCKET, FD_ACCEPT|FD_CLOSE); InternetAddr.sin_family = AF_INET; InternetAddr.sin_addr.s_addr = htonl(INADDR_ANY); InternetAddr.sin_port = htons(PORT);  if (bind(Listen, (PSOCKADDR) &InternetAddr, sizeof(InternetAddr))    == SOCKET_ERROR) {  MessageBox(hwnd, TEXT("bind() failed"), TEXT("error"), MB_OK);  ExitProcess(1); } if (listen(Listen, 5)) {  MessageBox(hwnd, TEXT("listen() failed"), TEXT("error"), MB_OK);  ExitProcess(1); } // Translate and dispatch window messages for the application thread while (GetMessage (&msg, NULL, 0, 0)) {  TranslateMessage (&msg) ;  DispatchMessage (&msg) ; } return msg.wParam ;} LRESULT CALLBACK WndProc (HWND hwnd, UINT message,        WPARAM wParam, LPARAM lParam){ HDC hdc ; PAINTSTRUCT ps ; RECT rect ; SOCKET Accept; LPSOCKET_INFORMATION SocketInfo; DWORD RecvBytes, SendBytes; DWORD Flags; switch (message) {  case WM_CREATE:   return 0 ;  case WM_PAINT:   hdc = BeginPaint (hwnd, &ps) ;   GetClientRect (hwnd, &rect) ;   DrawText (hdc, TEXT ("Server Started!"), -1, &rect,   DT_SINGLELINE | DT_CENTER | DT_VCENTER) ;   EndPaint (hwnd, &ps) ;   return 0 ;  case WM_DESTROY:   PostQuitMessage (0) ;   return 0 ;   case WM_SOCKET:   if (WSAGETSELECTERROR(lParam))   {    MessageBox(...);    FreeSocketInformation(wParam);   }    else   {    switch(WSAGETSELECTEVENT(lParam))    {     case FD_ACCEPT:      if ((Accept = accept(wParam, NULL, NULL)) == INVALID_SOCKET)      {        MessageBox(...);       break;      }      // Create a socket information structure to associate with the      // socket for processing I/O.      CreateSocketInformation(Accept, hwnd);      WSAAsyncSelect(Accept, hwnd, WM_SOCKET,          FD_READ|FD_WRITE|FD_CLOSE);      break;      case FD_READ:      SocketInfo = GetSocketInformation(wParam);      // Read data only if the receive buffer is empty.      if (SocketInfo->BytesRECV != 0)      {       SocketInfo->RecvPosted = TRUE;       return 0;      }      else      {       SocketInfo->DataBuf.buf = SocketInfo->Buffer;       SocketInfo->DataBuf.len = DATA_BUFSIZE;       Flags = 0;       if (WSARecv(SocketInfo->Socket, &(SocketInfo->DataBuf),            1, &RecvBytes, &Flags, NULL, NULL) == SOCKET_ERROR)       {        if (WSAGetLastError() != WSAEWOULDBLOCK)        {         MessageBox(...);         FreeSocketInformation(wParam);         return 0;        }       }        else // No error so update the byte count        SocketInfo->BytesRECV = RecvBytes;      }      // DO NOT BREAK HERE SINCE WE GOT A SUCCESSFUL RECV.       // Go ahead and begin writing data to the client.       case FD_WRITE:        SocketInfo = GetSocketInformation(wParam);       if (SocketInfo->BytesRECV > SocketInfo->BytesSEND)       {        SocketInfo->DataBuf.buf =          SocketInfo->Buffer + SocketInfo->BytesSEND;        SocketInfo->DataBuf.len =          SocketInfo->BytesRECV - SocketInfo->BytesSEND;        if (WSASend(SocketInfo->Socket, &(SocketInfo->DataBuf),             1, &SendBytes, 0,NULL, NULL) == SOCKET_ERROR)        {         if (WSAGetLastError() != WSAEWOULDBLOCK)         {          MessageBox(...);          FreeSocketInformation(wParam);          return 0;         }        }         else // No error so update the byte count         SocketInfo->BytesSEND += SendBytes;       }        if (SocketInfo->BytesSEND == SocketInfo->BytesRECV)       {        SocketInfo->BytesSEND = 0;        SocketInfo->BytesRECV = 0;        // If a RECV occurred during our SENDs then we need to post        // an FD_READ notification on the socket.         if (SocketInfo->RecvPosted == TRUE)        {         SocketInfo->RecvPosted = FALSE;         PostMessage(hwnd, WM_SOCKET, wParam, FD_READ);        }       }       if(SocketInfo->DataBuf.buf != NULL)        MessageBox(hwnd, SocketInfo->DataBuf.buf,            TEXT("Received"), MB_OK);       break;       case FD_CLOSE:       FreeSocketInformation(wParam);       break;    }   }   return 0; } return DefWindowProc(hwnd, message, wParam, lParam);} void CreateSocketInformation(SOCKET s, HWND hwnd){ LPSOCKET_INFORMATION SI; if ((SI = (LPSOCKET_INFORMATION) GlobalAlloc(GPTR, sizeof(SOCKET_INFORMATION))) == NULL) {  MessageBox(...);  return; } // Prepare SocketInfo structure for use. SI->Socket = s; SI->RecvPosted = FALSE; SI->BytesSEND = 0; SI->BytesRECV = 0; SI->Next = SocketInfoList; SocketInfoList = SI;} LPSOCKET_INFORMATION GetSocketInformation(SOCKET s){ SOCKET_INFORMATION *SI = SocketInfoList; while(SI) {  if (SI->Socket == s)  return SI;  SI = SI->Next; } return NULL;} void FreeSocketInformation(SOCKET s){ SOCKET_INFORMATION *SI = SocketInfoList; SOCKET_INFORMATION *PrevSI = NULL; while(SI) {  if (SI->Socket == s)  {   if (PrevSI)    PrevSI->Next = SI->Next;   else    SocketInfoList = SI->Next;   closesocket(SI->Socket);   GlobalFree(SI);   return;  }  PrevSI = SI;  SI = SI->Next; }} 服务器就这样建好了,只需要一个客户机就可以通信了,具体的代码我就不再贴了,各位可以自己设计客户机,或者去下载区下载源程序。最后向大家推荐《Windows网络编程技术》,真的不错。 本文中部分内容翻译自MSDN,客户机程序使用的是《Windows网络编程技术》中的例子

阅读全文(1970) | 回复(0) | 编辑 | 精华


发表评论:
昵称:
密码:
主页:
标题:
验证码:  (不区分大小写,请仔细填写,输错需重写评论内容!)

 

 

 


站点首页 | 联系我们 | 博客注册 | 博客登陆

Sponsored By W3CHINA
W3CHINA Blog 0.8 Processed in 0.031 second(s), page refreshed 144336677 times.
《全国人大常委会关于维护互联网安全的决定》  《计算机信息网络国际联网安全保护管理办法》
苏ICP备05006046号