Windows平台下WSAAsyncSelect 模型 服务器

本文介绍了一个使用WinSock的异步选择机制实现的简单服务器程序。该程序通过Windows消息循环来处理网络事件,包括接受新连接、读取数据等。文章详细展示了如何创建Socket、设置监听、绑定地址及使用WSAAsyncSelect函数。
#include "stdafx.h"
#include <winsock2.h>
#include <iostream>
#include "winuser.h"
#pragma comment( lib, "ws2_32.lib" )

using namespace std;


const int MAXDATASIZE    = 128;
const int BACKLOG        = 10;      // 指定等待连接队列的最大长度
const int WM_SOCKET      = ( WM_USER + 1);
const int BUF_SIZE       = 256;

struct _SOCKET_INFOMATION
{
      char    Buffer [MAXDATASIZE];     // 发送和接收数据缓冲区
      WSABUF  DataBuf ;                 // 定义发送和接收数据缓冲区,保护缓冲区在内的长度和内容
      SOCKET  Socket ;                  // 与客户端进行通信的 socket
      _SOCKET_INFOMATION* Next ;        // 指向下一个Socket 信息
};

typedef _SOCKET_INFOMATION   SOCKET_INFOMATION;
typedef _SOCKET_INFOMATION LPSOCKET_INFOMATION;

SOCKET Accept;                       // 监听的SOCKET
LPSOCKET_INFOMATION   SocketInfoList; // 所有socket 的信息列表
char    buf[ MAXDATASIZE];


BOOL                   CreateSocketInformation ( SOCKET s );
LPSOCKET_INFOMATION    GetSocketInfomation( SOCKET s );
HWND                   MakeWorkerWindow();
LRESULT CALLBACK      WindowProc( HWND hwdn, UINT uMsg , WPARAM wParam, LPARAM lParam );

enum
{
      MAIN_RETURN_ERROR           =  -1,
      MAIN_RETURN_NORMAL          =   0,
};

// 创建 SOCKET
BOOL CreateSocketInformation( SOCKET s )
{
      LPSOCKET_INFOMATION SI ;
      // SI 分配空间
      if( ( SI = (LPSOCKET_INFOMATION) GlobalAlloc( GPTR , sizeof ( SOCKET_INFOMATION ) ) ) == NULL )
     {
           cout<<"GlobalAlloc Failed with Error "<< GetLastError();
           return FALSE ;
     }

      // 向前插入法
      SI->Socket        = s;
      SI->Next          = SocketInfoList;
      SocketInfoList   = SI ;

      return TRUE ;
}

// 调用 GetSocketInfomation 来获取 Socket 的消息
LPSOCKET_INFOMATION    GetSocketInfomation( SOCKET s )
{
      LPSOCKET_INFOMATION si = SocketInfoList;

      while( si )
     {
           if( si ->Socket == s )
               return si ;

           si = si ->Next;
     }

      return NULL ;
}

HWND MakeWorkerWindow( )
{
      // 定义registerClass 的注册窗口
      WNDCLASSEX wndclass ;
      char*   ProviderClass = "AsyncSelect";
      HWND  Window ;

      wndclass.style = CS_HREDRAW | CS_VREDRAW;
      wndclass.cbClsExtra = wndclass. cbWndExtra = 0;
      wndclass.hInstance = NULL;
      wndclass.hIcon      = LoadIcon( NULL , IDI_WARNING );
      wndclass.hCursor    = LoadCursor( NULL, IDC_ARROW );
      wndclass.hbrBackground = (HBRUSH )GetStockObject( WHITE_BRUSH);
      wndclass.lpszMenuName   = NULL;
      wndclass.lpszClassName = ProviderClass;
      wndclass.lpfnWndProc = (WNDPROC) WindowProc;

      if( RegisterClassEx ( &wndclass) == 0 )
     {
           cout<<"RegisterClass failed with error "<< GetLastError()<<endl ;
           return NULL ;
     }

      if( ( Window = CreateWindow( ProviderClass, "" , WS_OVERLAPPEDWINDOW ,
                                 CW_USEDEFAULT, CW_USEDEFAULT , CW_USEDEFAULT, CW_USEDEFAULT,
                                     NULL, NULL , NULL, NULL ) ) == NULL )
     {
           cout<<"CreateWindow failed with error "<< GetLastError()<<endl ;
           return NULL ;
     }

      return Window ;
}

LRESULT CALLBACK WindowProc( HWND hwdn, UINT uMsg , WPARAM wParam , LPARAM lParam )
{
      LPSOCKET_INFOMATION SocketInfo ;
      if( uMsg == WM_SOCKET )
     {
           if( WSAGETSELECTERROR ( lParam ) )
               cout<<"Socket failed with error with "<< WSAGETSELECTERROR( lParam )<<endl;
           else
          {
               switch( WSAGETSELECTEVENT ( lParam) )
              {
               case FD_ACCEPT :
                   {
                         if( Accept = accept( wParam, NULL, NULL ) == INVALID_SOCKET )
                              cout<<"" <<endl;
                         else
                        {
                              CreateSocketInformation ( Accept );
                              WSAAsyncSelect( Accept , hwdn, WM_SOCKET , FD_READ| FD_WRITE|FD_CLOSE );
                        }
                   }
                    break;
               case FD_READ :
                   {
                         SocketInfo = GetSocketInfomation ( wParam );
                         int Recv    = recv( SocketInfo ->Socket, buf, MAXDATASIZE , 0 );
                         buf[Recv ]  = '\0';
                         if( Recv > 0 )
                              cout<<"Received:  %s "<< endl;
                   }
                    break;
              }
          }

           return 0;
     }

      return DefWindowProc ( hwdn, uMsg, wParam , lParam );
}


int main( int argc , char* argv[] )
{
      MSG    msg ;
      DWORD  Ret ;
      SOCKET socketfd ;
      HWND   Window ;
     
      if( ( Window = MakeWorkerWindow() ) == NULL )
           return 0;

      WSADATA wsaData ;
      if( WSAStartup ( MAKEWORD( 2, 2 ), & wsaData ) != 0 )
     {
           cout<<"WSAStartup 无法初始化 !" <<endl ;
           return MAIN_RETURN_ERROR ;
     }

      socketfd= socket ( AF_INET, SOCK_STREAM, 0 );
      WSAAsyncSelect( socketfd , Window, WM_SOCKET, FD_ACCEPT );

      struct sockaddr_in my_addr;
      my_addr.sin_family   = AF_INET;
      my_addr.sin_port     = htons( 9990 );   // 服务器端口号
      my_addr.sin_addr .S_un. S_addr = htonl ( INADDR_ANY );

      // 绑定
      int    retVal ;
      retVal = bind ( socketfd, ( const struct sockaddr *)&my_addr , sizeof( struct sockaddr_in ) );
      if( SOCKET_ERROR == retVal )
     {
           cout<<"bind failed !" <<"   Reson: "<< WSAGetLastError()<<endl ;
           closesocket( socketfd );
           WSACleanup();
           return -1;
     }

      // 监听
      retVal = listen ( socketfd, BACKLOG );
      if( SOCKET_ERROR == retVal )
     {
           cout<<"listen failed !" <<" Reson:"<< WSAGetLastError()<<endl ;
           closesocket( socketfd );
           WSACleanup();
           return -1;
     }

      while( Ret = GetMessage( & msg, NULL , 0, 0 ) )
     {
           if( Ret == -1 )
          {
               cout<<"GetMessage failed with error at "<< GetLastError()<<endl ;
               return 0;
          }

           TranslateMessage( &msg );
           DispatchMessage( &msg );
     }

      system("pause" );
      return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值