现在的位置: 首页 > 综合 > 正文

TCP流式套接字的异步事件WSAAsyncSelect编程

2013年12月23日 ⁄ 综合 ⁄ 共 5917字 ⁄ 字号 评论关闭

WSAAsyncSelect( )是Winsock提供的一个适合于Windows编程使用的函数,它允许在一个套接口上当发生特定的网络事件时,给Windows网络应用程序(窗口或对话框)发送一个消息(事件通知)。

WSAAsyncSelect函数原型如下:

int WSAAsyncSelect(
    SOCKET s,  //标识一个需要事件通知的套接口描述符
    HWND hWnd,  //标识一个在网络事件发生时要想收到消息的窗口或对话框的句柄
    u_int wMsg,  //在网络事件发生时要接收的消息,该消息会投递到由hWnd句柄指定的窗口或对话框
    long lEvent  //位屏蔽码,用于指明应用程序感兴趣的网络事件集合
);

     若应用程序对一个套接口s调用了WSAAsyncSelect( )函数,那么套接口s的模式会自动从阻塞模式变成非阻塞模式。如果应用程序同时对多个网络事件感兴趣,那么只需对各种类型的网络事件执行按位或(OR)的运算即可。进行一次WSAAsyncSelect( )调用,将使为同一个套接口启动的所有以前的WSAAsyncSelect( )调用作废。如果要取消所有的通知,也就是指出Windows Sockets的实现不再在套接口上发送任何和网络事件相关的消息,则把lEvent字段置为0,然后调用WSAAsyncSelect( )。当某一套接口s上发生了一个已命名的网络事件时,应用程序窗口hWnd会接收到消息wMsg。应用程序窗口例程的wParam参数标识了网络事件发生的套接口。lParam参数的低位字指明了发生的网络事件,高位字则含有一个错误代码,该错误代码可以是Winsock2.h中定义的任何错误。

以下为测试WSAAsyncSelect()函数的程序,一个服务器端两个客户端

下面是服务器端程序:

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
#define WM_SOCKET WM_USER+101 
#include <WINSOCK2.H> 
/*#include <windows.h>*/ 
#pragma comment(lib,"WS2_32"
//----------------窗口过程函数的声明------------- 
LRESULT CALLBACK WindowProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam); 
//----------------WinMain()函数------------------ 
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd ) 

    WNDCLASS wc; 
    wc.style=CS_HREDRAW|CS_VREDRAW; 
    wc.lpfnWndProc=WindowProc; 
    wc.cbClsExtra=0
    wc.cbWndExtra=0
    wc.hInstance=hInstance; 
    wc.hIcon=LoadIcon(NULL,IDI_EXCLAMATION); 
    wc.hCursor=LoadCursor(NULL,IDC_ARROW); 
    wc.hbrBackground=(HBRUSH)GetStockObject(BLACK_BRUSH); 
    wc.lpszMenuName=NULL; 
    wc.lpszClassName="Test"
    //---注册窗口类---- 
    RegisterClass(&wc); 
    //---创建窗口---- 
    HWND hwnd=CreateWindow("Test","窗口标题",WS_SYSMENU,300,0,600,400,NULL,NULL,hInstance,NULL); 
    if (hwnd==NULL) 
    { 
        MessageBox(hwnd,"创建窗口出错","标题栏提升",MB_OK); 
        return 1
    } 
    //---显示窗口---- 
    ShowWindow(hwnd,SW_SHOWNORMAL); 
    UpdateWindow(hwnd); 
    //---socket----- 
    WSADATA wsaData; 
    WORD wVersionRequested=MAKEWORD(2,2); 
    if (WSAStartup(wVersionRequested,&wsaData)!=0
    { 
        MessageBox(NULL,"WSAStartup() Failed","调用失败",0); 
        return 1
    } 
    SOCKET s=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP); 
    if (s==INVALID_SOCKET) 
    { 
        MessageBox(NULL,"socket() Failed","调用失败",0); 
        return 1
    }     
    sockaddr_in sin; 
    sin.sin_family=AF_INET; 
    sin.sin_port=htons(1111); 
    sin.sin_addr.S_un.S_addr=inet_addr("192.168.31.1"); 
    if (bind(s,(sockaddr*)&sin,sizeof(sin))==SOCKET_ERROR) 
    { 
        MessageBox(NULL,"bind() Failed","调用失败",0); 
        return 1
    } 
    if (listen(s,3)==SOCKET_ERROR) 
    { 
        MessageBox(NULL,"listen() Failed","调用失败",0); 
        return 1
    } 
    else 
        MessageBox(hwnd,"进入监听状态!","标题栏提示",MB_OK); 
    WSAAsyncSelect(s,hwnd,WM_SOCKET,FD_ACCEPT|FD_CLOSE); 
    //---消息循环---- 
    MSG msg; 
    while (GetMessage(&msg,0,0,0)) 
    { 
        TranslateMessage(&msg); 
        DispatchMessage(&msg); 
    } 
    closesocket(s); 
    WSACleanup(); 
    return msg.wParam; 

//-------------------窗口过程---------------------- 
LRESULT CALLBACK WindowProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam) 

    switch(uMsg) 
    { 
    case WM_SOCKET: 
        { 
            SOCKET ss=wParam;   //wParam参数标志了网络事件发生的套接口 
            if (WSAGETSELECTERROR(lParam)) 
            { 
                closesocket(ss); 
                return 0
            } 
            switch (WSAGETSELECTEVENT(lParam)) 
            { 
            case FD_ACCEPT:   //-----①连接请求到来 
                { 
                     sockaddr_in Cadd; 
                     int Cadd_len=sizeof(Cadd); 
                    SOCKET sNew=accept(ss,(sockaddr*)&Cadd,&Cadd_len); 
                    if (ss==INVALID_SOCKET)                     
                        MessageBox(hwnd,"调用accept()失败!","标题栏提示",MB_OK);                     
                    WSAAsyncSelect(sNew,hwnd,WM_SOCKET,FD_READ|FD_CLOSE); 
                }break
            case FD_READ:   //-----②数据发送来 
                { 
                    char cbuf[256]; 
                    memset(cbuf,0,256); 
                    int cRecv=recv(ss,cbuf,256,0); 
                    if ((cRecv==SOCKET_ERROR&& WSAGetLastError() == WSAECONNRESET)|| cRecv==0
                    { 
                        MessageBox(hwnd,"调用recv()失败!","标题栏提示",MB_OK); 
                        closesocket(ss); 
                    } 
                    else if (cRecv>0
                    { 
                        MessageBox(hwnd,cbuf,"收到的信息",MB_OK);     
                        char Sbuf[]="Hello client!I am server"
                        int isend=send(ss,Sbuf,sizeof(Sbuf),0); 
                        if (isend==SOCKET_ERROR || isend<=0
                        { 
                            MessageBox(hwnd,"发送消息失败!","标题栏提示",MB_OK);                             
                        } 
                        else 
                            MessageBox(hwnd,"已经发信息到客户端!","标题栏提示",MB_OK); 
                    } 
                }break
            case FD_CLOSE:    //----③关闭连接 
                { 
                    closesocket(ss); 
                } 
                break
            } 
        } 
        break
    case WM_CLOSE: 
        if (IDYES==MessageBox(hwnd,"是否确定退出?","message",MB_YESNO)) 
            DestroyWindow(hwnd); 
        break
    case WM_DESTROY: 
        PostQuitMessage(0); 
        break
    default
        return DefWindowProc(hwnd,uMsg,wParam,lParam); 
    } 
    return 0

客户端与上两次的都一样,这里不再给出。详见这里【TCP流式套接字的阻塞模式编程】http://blog.csdn.net/akof1314/archive/2010/05/13/5588265.aspx1

先启动服务器端,再启动1号客户端,接着启动2号客户端,就会看到如图所示:

抱歉!评论已关闭.