Windows消息循环和服务器循环

时间:2016-11-16 11:54:02

标签: c++ winapi

我使用Win32 API创建了一个窗口,它需要输入一个消息循环:

while (GetMessage(&msg, nullptr, 0, 0))
{
    TranslateMessage(&msg);
    DispatchMessage(&msg);
}

如果主线程处理UI消息,如何创建套接字服务器并开始接收客户端?

我尝试使用CreateThread()中的WinMain()将所有服务器代码放入一个帖子中,但它只是因为错误而崩溃:

  

test.exe中0x00000000处抛出异常:0xC0000005:访问冲突执行位置0x00000000。

这是线程代码:

DWORD WINAPI ThreadProc(LPVOID lpParameter)
{
    // Initialize Winsock
    WSADATA wsaData;
    auto iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
    if (iResult != 0) {
        printf("WSAStartup failed with error: %d\n", iResult);
        return EXIT_FAILURE;
    }

    addrinfo hints;
    ZeroMemory(&hints, sizeof(hints));
    hints.ai_family = AF_INET;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;
    hints.ai_flags = AI_PASSIVE;

    // Resolve the server address and port
    PADDRINFOA pAddrInfo = nullptr;
    iResult = getaddrinfo(nullptr, PORT, &hints, &pAddrInfo);
    if (iResult != 0) {
        printf("getaddrinfo failed with error: %d\n", iResult);
        WSACleanup();
        return EXIT_FAILURE;
    }

    while (true) {
        // Create a SOCKET for connecting to server
        auto ListenSocket = socket(pAddrInfo->ai_family, pAddrInfo->ai_socktype, pAddrInfo->ai_protocol);
        if (ListenSocket == INVALID_SOCKET) {
            printf("socket failed with error: %ld\n", WSAGetLastError());
            freeaddrinfo(pAddrInfo);
            WSACleanup();
            return EXIT_FAILURE;
        }

        // Setup the TCP listening socket
        iResult = bind(ListenSocket, pAddrInfo->ai_addr, static_cast<int>(pAddrInfo->ai_addrlen));
        if (iResult == SOCKET_ERROR) {
            printf("bind failed with error: %d\n", WSAGetLastError());
            freeaddrinfo(pAddrInfo);
            closesocket(ListenSocket);
            WSACleanup();
            return EXIT_FAILURE;
        }

        freeaddrinfo(pAddrInfo);

        iResult = listen(ListenSocket, SOMAXCONN);
        if (iResult == SOCKET_ERROR) {
            printf("listen failed with error: %d\n", WSAGetLastError());
            closesocket(ListenSocket);
            WSACleanup();
            return EXIT_FAILURE;
        }

        // Accept a client socket
        auto ClientSocket = accept(ListenSocket, nullptr, nullptr);
        if (ClientSocket == INVALID_SOCKET) {
            printf("accept failed with error: %d\n", WSAGetLastError());
            closesocket(ListenSocket);
            WSACleanup();
            return EXIT_FAILURE;
        }

        // No longer need server socket
        closesocket(ListenSocket);

        // Receive until the peer shuts down the connection
        for (;;)
        {
            char recvbuf[1] = { 0 };
            auto cbLen = recv(ClientSocket, recvbuf, sizeof(recvbuf), 0);

            if (cbLen > 0) {
                if (recvbuf[0] == 0xDA)
                {
                    Hide();
                }

                continue;
            }
            else if (cbLen == 0) {
                printf("Connection closing...\n");
                break;
            }
            else {
                printf("recv failed with error: %d\n", WSAGetLastError());
                closesocket(ClientSocket);
                WSACleanup();
                return EXIT_FAILURE;
            }
        }

        // shutdown receive operations since we're done
        iResult = shutdown(ClientSocket, SD_RECEIVE);
        if (iResult == SOCKET_ERROR) {
            printf("shutdown failed with error: %d\n", WSAGetLastError());
            closesocket(ClientSocket);
            WSACleanup();
            return EXIT_FAILURE;
        }

        // cleanup
        closesocket(ClientSocket);
    }
    WSACleanup();

    return 0;
}

1 个答案:

答案 0 :(得分:0)

这是一个非常令人困惑的问题,因为它在标题中提出了一个问题,但内容解决了另一个问题(线程崩溃)。

解决主要问题:Microsoft确实添加了一种以GUI线程友好的方式处理套接字通信的方法:WSAAsyncSelect。这会将套接字事件作为消息发送到应用程序消息队列 - 通常会创建一个不可见的窗口来处理消息。