未调用异步 Winsock 服务器的 WndProc

Posted

技术标签:

【中文标题】未调用异步 Winsock 服务器的 WndProc【英文标题】:Asynchronous Winsock Server's WndProc not being called 【发布时间】:2014-03-01 07:28:54 【问题描述】:

我正在尝试学习制作一个合适的 Winsock 服务器,并通过一些尝试和努力获得了以下代码以及在线找到的示例。我的服务器确实出现在“netstat -an”中,并且可以通过 Hercules IO 调试器应用程序连接。不幸的是,在 WndProc 中看到的任何消息框都没有出现。

Sockets.h:

#include <winsock.h>

#pragma comment(lib, "ws2_32.lib")

SOCKET s;
WSADATA w;
#define MY_MESSAGE_NOTIFICATION      1048

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

    MessageBox(hwnd, (LPCWSTR)L"Test1", (LPCWSTR)L"Test1", MB_OK);
    switch (message)
    
    case MY_MESSAGE_NOTIFICATION:
        
            switch (lParam)
            
            case FD_ACCEPT:
                break;
            case FD_CONNECT:
                MessageBox(hwnd,(LPCWSTR)L"Test2",(LPCWSTR)L"Test2",MB_OK);
                break;
            case FD_READ:
                char buffer[80];
                memset(buffer, 0, sizeof(buffer)); 
                recv (s, buffer, sizeof(buffer)-1, 0); 
                MessageBox(hwnd, (LPCWSTR)buffer, (LPCWSTR)L"Captured Text…", MB_OK);
                break;
            case FD_CLOSE:
                break;
            
        
        break;
    default:
        return DefWindowProc(hwnd, message, wParam, lParam);
    


int ListenOnPort(int portno)

    int error = WSAStartup (0x0202, &w);
    if (error)
    
        return false;
    
    if (w.wVersion != 0x0202)
    
        WSACleanup ();
        return false;
    
    SOCKADDR_IN addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons (portno);
    addr.sin_addr.s_addr = htonl (INADDR_ANY);  
    s = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (s == INVALID_SOCKET)
    
        return false;
    
    if (bind(s, (LPSOCKADDR)&addr, sizeof(addr)) == SOCKET_ERROR)
    
        return false;
    
    listen(s, SOMAXCONN);
    WSAAsyncSelect (s, GetConsoleWindow(), MY_MESSAGE_NOTIFICATION, (FD_ACCEPT | FD_CONNECT |
         FD_READ | FD_CLOSE));

【问题讨论】:

尝试将实际窗口的句柄传递给 WSAAsyncSelect.. 传递 GetConsoleWindow 似乎不对.. 我进行了测试,以确保它是正确的句柄,主 cpp 中有一个消息框,其中 GetConsoleWindow 作为 hwnd 正确绑定它。如果你能告诉我一个更好的功能,我会尝试的。 我不确定是否允许从窗口过程中调用 MessageBox。也许尝试将程序编译为控制台应用程序(控制台应用程序仍然可以创建窗口!)并使用printf 代替您的调试消息? 窗口过程没有被调用的常见原因是忘记执行消息循环和忘记执行错误检查。在 sn-p 中没有消息循环的迹象,有大量迹象表明缺乏错误检查。 从不忽略 C 函数的返回值。 我已经在编译为控制台应用程序——没有其他窗口。 【参考方案1】:

您告诉WSAAsyncSelect() 向不属于您的 HWND 发送消息。除非您手动对该窗口进行子类化并将WndProc() 连接到它,否则WndProc() 将永远不会收到套接字消息。您需要创建自己的 HWND。并确保您的代码中还有一个消息循环,否则您的 HWND 将永远不会收到消息。

【讨论】:

【参考方案2】:

你为什么不直接检查 WSAAsyncSelect 的返回值,它应该会告诉你哪里出了问题,它似乎甚至没有在窗口上注册。

通常您应该避免将控制台窗口用作 HWND (GetConsoleWindow()),因为它是由系统处理的特殊窗口,因此它的行为可能不同。 还有什么叫 WndProc 函数?看起来没什么,因为您使用 有自己的控制台窗口 WndProc!

所以只需尝试为自己创建一个窗口,并在 WSAAsyncSelect 调用中指定它并使其不可见,这样就不会打扰用户,完成后只需销毁窗口!

【讨论】:

以上是关于未调用异步 Winsock 服务器的 WndProc的主要内容,如果未能解决你的问题,请参考以下文章

WINSOCK.04.异步选择模型

C++ winsock服务器中非阻塞模式与异步套接字的区别

winsock套接字错误

C++ winsock 错误

WinSock 异步I/O模型-4

winsock:蓝牙客户端-服务器未连接