天天看点

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

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> 

#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号客户端,就会看到如图所示:

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

继续阅读