WSAAsyncSelect模型

WSAAsyncSelect模型允许程序以windows消息的形式接受网络事件通知

WSAAsyncSelect函数自动把套接字设为非阻塞模式,并且为套接字绑定一个窗口句柄,当有网络事件发生时,便向这个窗口发送消息

int WSAAsyncSelect(
    SOCKET s, //套接字句柄
    HWND hWnd,//指定一个窗口句柄
    u_int wMsg,//网络事件到来的消息ID
    long lEvent//指定那些需要发送
);

FD_READ:接收对方发送的数据包

FD_WRITE:继续发送数据

FD_ACCEPT:有连接进入

FD_CONNECT:连接对方主机

FD_CLOSE:连接被关闭

调用WSAAsyncSelect函数监听套接字

::WSAAsyncSelect(sListen,hWnd,WM_SOCKET,FD_ACCEPT|FD_CLOSE);

成功调用后,应用程序开始以windows消息形式在窗口函数接受网络事件通知

LRESULT CALLBACK WindowProc(HWND hWnd,
                            UINT uMsg,
                            WPARAM wParam,//发送网络事件的套接字句柄
                            LPARAM lParam//指定了发生的网络事件
);

下面是简单的TCP服务器程序,接受客户端的连接请求,打印出接收的数据。

// WSATCPSERVER.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <winsock2.h>
#include <stdio.h> 
#pragma comment(lib,"WS2_32")
class CInitSock
 {
 public:
     CInitSock(BYTE minorVer=2,BYTE majorVer=2)
     {
         WSADATA wsaData;
         WORD sockVersion = MAKEWORD(minorVer,majorVer);
         if(::WSAStartup(sockVersion,&wsaData)!=0)
         {
             exit(0);
         }
     }
     ~CInitSock()
     {
         ::WSACleanup();
     }
}; 
CInitSock initSock;
LRESULT CALLBACK WindowProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam);
int _tmain(int argc, _TCHAR* argv[])
{
    char szClassName[] = "MainWClass";
    WNDCLASSEX wndclass;
    //用描述主窗口的参数填充WNDCLASSEX结构
    wndclass.cbSize = sizeof(wndclass);
    wndclass.style = CS_HREDRAW|CS_VREDRAW;
    wndclass.lpfnWndProc = WindowProc;
    wndclass.cbWndExtra = 0;
    wndclass.cbClsExtra = 0;
    wndclass.hInstance = NULL;
    wndclass.hIcon = ::LoadIcon(NULL,IDI_APPLICATION);
    wndclass.hCursor = ::LoadCursor(NULL,IDC_ARROW);
    wndclass.hbrBackground = (HBRUSH)::GetStockObject(WHITE_BRUSH);
    wndclass.lpszMenuName = NULL;
    wndclass.lpszClassName = szClassName;
    wndclass.hIconSm = NULL;
    ::RegisterClassEx(&wndclass);
    //创建主窗口
    HWND hWnd = ::CreateWindowEx(
        0,
        szClassName,
        "",
        WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT,
        CW_USEDEFAULT,
        CW_USEDEFAULT,
        CW_USEDEFAULT,
        NULL,
        NULL,
        NULL,
        NULL);
    if(hWnd == NULL)
    {
        ::MessageBox(NULL,"创建窗口出错!","error",MB_OK);
        return -1;
    }
    USHORT nPort = 4567;
    SOCKET sListen = ::socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
    sockaddr_in sin;
    sin.sin_family = AF_INET;
    sin.sin_port = htons(nPort);
    sin.sin_addr.S_un.S_addr = INADDR_ANY;
    if(::bind(sListen,(sockaddr*)&sin,sizeof(sin)) == SOCKET_ERROR)
    {
         printf("Failed bind()\n");
         return -1;
    }
    //套接字设为窗口通知消息类型
    ::WSAAsyncSelect(sListen,hWnd,WM_SOCKET,FD_ACCEPT|FD_CLOSE);
    ::listen(sListen,5);
    //消息队列中取出消息
    MSG msg;
    while(::GetMessage(&msg,NULL,0,0))
    {
        ::TranslateMessage(&msg);//转化键盘消息
        ::DispatchMessage(&msg);//将消息发送到相应窗口函数
    }

    return msg.wParam;//当GETMESSAGE返回0时结束
}
LRESULT CALLBACK WindowProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
    switch(uMsg)
    {
    case WM_SOCKET:
        {
            SOCKET s=wParam;
            //查看是否出错
            if(WSAGETSELECTERROR(lParam))
            {
                ::closesocket(s);
                return 0;
            }
            switch(WSAGETSELECTEVENT(lParam))
            {
            case FD_ACCEPT:
                {
                    SOCKET client = ::accept(s,NULL,NULL);
                    ::WSAAsyncSelect(client,hWnd,WM_SOCKET,FD_READ|FD_WRITE|FD_CLOSE);
                }
                break;
            case FD_WRITE:
                {

                }
                break;
            case FD_READ:
                {
                    char szText[1024]={0};
                    if(::recv(s,szText,1024,0) == -1)
                        ::closesocket(s);
                    else
                        printf("接收数据:%s",szText);
                }
                break;
            case FD_CLOSE:
                {
                    ::closesocket(s);
                }
                break;
            }
        }
    case WM_DESTROY:
        ::PostQuitMessage(0);
        return 0;
    }
    //不处理的消息交给系统默认处理
    return ::DefWindowProc(hWnd,uMsg,wParam,lParam);
}

好多错误啊...首先 char 不能转成LPSZ  其次,WM_SOCKET不认,为什么......哎

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏喵了个咪的博客空间

EMQ百万级MQTT消息服务(TLS Docker Golang)

5233
来自专栏敏捷开发&项目管理

Bat file 安装和卸载同级目录下的.net 服务

今天得到个需求 客户需要用batch file 安装和卸载服务,网上搜了一把例子,都只解决了单个问题,我来稍微总结一下 安装服务 @ECHO OFF REM T...

3796
来自专栏向治洪

android PakageManagerService启动流程分析

PakageManagerService的启动流程图 ? 1.PakageManagerService概述 PakageManagerService是andro...

53210
来自专栏移动端周边技术扩展

iOS打开系统功能对应的URL

1853
来自专栏我的博客

filter_input()详解,$_GET,$_POST,$_ENV,$_SERVER,$_SESSION,$_REQUEST

filter_input() 函数从脚本外部获取输入,并进行过滤。 本函数用于对来自非安全来源的变量进行验证,比如用户的输入。 本函数可从各种来源获取输入: I...

3465
来自专栏乐沙弥的世界

使用 SQLNET.EXPIRE_TIME 清除僵死连接

    数据库连接的客户端异常断开后,其占有的相应并没有被释放,如从v$session视图中依旧可以看到对应的session处于inactive,且对应的服务器...

2952
来自专栏landv

c语言_头文件_windows.h

2193
来自专栏施炯的IoT开发专栏

Battery Status on Windows Mobile

    大家知道,我们可以通过Start->Settings->Systems->Power来查看系统的电池情况,包括电池的类型,剩余的电量等等,如下图1所示:...

2086
来自专栏C++

Windows核心编程:第7章 线程调度、优先级和关联性

1223
来自专栏技术小讲堂

LINQ to SQL(2):生成对象模型

在LINQ to SQL中,可以使用自己的编程语言的对象模型映射到关系数据库,在上一节课,已经有一部分内容,简单的介绍了一下这种对象模型的结构,这一节,我们主要...

2884

扫码关注云+社区

领取腾讯云代金券