如何使 WSAAsyncSelect 在应用程序控制台中启动?

Posted

技术标签:

【中文标题】如何使 WSAAsyncSelect 在应用程序控制台中启动?【英文标题】:How to make WSAAsyncSelect start in an application console? 【发布时间】:2014-05-08 21:33:45 【问题描述】:

我一直在尝试学习如何在 C++ 中使用套接字,所以我搜索了一个我阅读的教程,该教程说有两种方法可以从套接字接收信息,第一种是通过无限循环不断检查recv,另一个正在使用异步套接字,我尝试使用异步但我得到错误10022我搜索错误,它说函数中有一个无效的参数,我猜它的句柄函数我用谷歌搜索了一个方法找到解决此运行时错误的方法,但我无法做到。

public: static bool ListenOnPort(int port)

    int error = WSAStartup(0x0202, &w);
    if (error)
    
        printf_s("Por alguna razón no se ha podido iniciar WSAStartup");
        WSACleanup();
        return false;
    
    if (w.wVersion != 0x0202)
    
        WSACleanup();

        return false;
    
    SOCKADDR_IN addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(port);
    addr.sin_addr.s_addr = htonl(INADDR_ANY);

    mysocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (mysocket == INVALID_SOCKET)
    
        printf_s("No se ha podido iniciar el socket 's'");
        Functions::CloseConnection();
        return false;
    
    listen(mysocket, SOMAXCONN);
    if (!WSAAsyncSelect(mysocket,Hwnd, MY_MESSAGE_NOTIFICATION, (FD_ACCEPT | FD_CONNECT |FD_READ | FD_CLOSE)))
    
        printf("\nWSAAsyncSelect initialized succesfully\n");
    
    else
    
        printf("\nAn error ocurred while executing WSAsyngSelect (%d)[1]\n", WSAGetLastError());
    
    if (bind(mysocket, (LPSOCKADDR)&addr, sizeof(addr)) == SOCKET_ERROR)
    
        printf("We coundnt bind");
        Functions::CloseConnection();
        return false;
    
    return true;

还有 WndProc 函数:

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)

    Hwnd = (HWND)GetModuleHandle(NULL);
    switch (message)
    
        case MY_MESSAGE_NOTIFICATION:
        
            switch (lParam)
            
                case FD_ACCEPT:
                
                    printf_s("There's a connection incomming\n");
                    accept(wParam, 0, 0);
                    break;
                
                case FD_CONNECT:
                
                    printf("A socket has just connected to the host.\n");
                    break;
                
                case FD_READ:
                
                    char buf[256];
                    memset(buf, 0, sizeof(buf));
                    recv(mysocket, buf, sizeof(buf)-1, 0);
                    break;
                
                case FD_CLOSE:
                
                    printf_s("A connection has just been shutted down.\n");
                    Functions::CloseConnection();
                    break;
                
            
        
        default:return DefWindowProc(hwnd, message, wParam, lParam);
    
    return 0;
    //break;

编辑:我的主要功能:

int main(int argc, char *argv[])

    //printf_s("Ingresa la dirección IP para conectar.\n");
    if (argc != 0)
    
        Functions::ListenOnPort(7182);
        while (true)
        
            if (Conectado == false)
            
                printf_s("\nConnecting to %s on port 7182\n", (char*)"127.0.0.1");
                Functions::ConnectToHost(7182, (char*)"127.0.0.1");
                cin.get();
            
            else
            
                Sleep(120);
            
        
    
    Functions::CloseConnection();
    return 0;

【问题讨论】:

错误发生在哪里?插座和控制台有什么关系?接收数据的方式不止两种。 当我在 ListenOnPort 函数上调用 WSAAsyncSelect 时出现错误。在那里我更新了调用函数的方式。 【参考方案1】:

这行代码不对:

Hwnd = (HWND)GetModuleHandle(NULL);

模块句柄的类型为HMODULE,与窗口句柄的类型为HWND 完全不同。你需要后者。

看起来好像您没有创建一个窗口。您需要致电CreateWindow 来做到这一点。您想通过将HWND_MESSAGE 传递给CreateWindowhWndParent 参数来创建仅消息窗口。您必须在调用WSAAsyncSelect 之前创建窗口,原因很明显,您需要有一个窗口句柄才能传递给WSAAsyncSelect

您还需要运行一个消息循环,以便发送您的套接字消息。您的程序似乎也缺少这一点。

这是一个相当复杂的主题。我建议你找到一些异步 Windows 套接字的示例代码并从那里开始。

【讨论】:

+1。不知道您可以使用 HWND_MESSAGE 而不是创建一个实体窗口并将其隐藏。 HWND_MESSAGE rocks. 好的,所以我尝试了你的方法,但每次我尝试 CreateWindow() 时总是得到错误代码 0。Hwnd = CreateWindow("MainWClass", "Titlebar", WS_OVERLAPPEDWINDOW, CW_DEFAULT, CW_DEFAULT, CW_DEFAULT, CW_DEFAULT,HWND_MESSAGE,(HMENU)NULL,(HINSTANCE)NULL,(LPVOID)NULL); if (Hwnd != NULL) printf("创建\n"); else printf("未创建 %d\n", GetLastError()); 在调用CreateWindow()之前,您是否通过RegisterClass()注册了"MainWClass"窗口类?此外,CreateWindows()hInstance 参数应该是调用进程的实际HINSTANCE(您可以使用GetModuleHandle(NULL)),并且必须与您传递给RegisterClass()hInstance 相同。 如果您确实设法获得了一个有效的HWND,请不要忘记它需要一个消息循环,否则您的WndProc() 将永远不会被调用。如果您不想经历所有这些 HWND 开销,请在单个循环中使用 WSAEventSelect()WSAWaitForMultipleEvents()

以上是关于如何使 WSAAsyncSelect 在应用程序控制台中启动?的主要内容,如果未能解决你的问题,请参考以下文章

windows下的IO模型之异步选择(WSAAsyncSelect)模型

WSAAsyncSelect 消息模型

网络IO模型-异步选择

SOCKET重叠I/O模型

如何在 Codeigniter 中使视图“可移植”?

如何配置单点触控应用程序?