Visual C ++跨线程发送消息

时间:2017-03-30 07:06:44

标签: c++ multithreading

我正在编写一个服务器应用程序,它等待ServerSocket对象并创建连接套接字。 每个连接都有一个SocketListener和一个用于传输数据的SocketSender。

每个SocketListener都是一个单独的线程。当客户端断开连接时,SocketListener向ServerSocket发送一条消息,告知它正在关闭,以便ServerSocket可以从列表中清除该连接的句柄。

但是,不知道为什么SocketListener线程没有收到该消息。我试图缩小消息过滤器,但没有运气。有人可以帮我这个。

DWORD ServerSocket::m_ThreadFunc() {
// Initialize Winsock
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != 0) {
    printf("WSAStartup failed\n");
    return 1;
}

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
iResult = getaddrinfo(NULL, DEFAULT_PORT_STR, &hints, &result);
if (iResult != 0) {
    printf("getaddrinfo failed\n");
    WSACleanup();
    return 1;
}

// Create a SOCKET for connecting to server
ListenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
if (ListenSocket == INVALID_SOCKET) {
    printf("socket failed\n");
    freeaddrinfo(result);
    WSACleanup();
    return 1;
}

// Setup the TCP listening socket
iResult = bind(ListenSocket, result->ai_addr, (int)result->ai_addrlen);
if (iResult == SOCKET_ERROR) {
    printf("bind failed\n");
    freeaddrinfo(result);
    closesocket(ListenSocket);
    WSACleanup();
    return 1;
}

freeaddrinfo(result);

iResult = listen(ListenSocket, SOMAXCONN);
if (iResult == SOCKET_ERROR) {
    printf("listen failed\n");
    closesocket(ListenSocket);
    WSACleanup();
    return 1;
}

// allow listener thread to report back its state
MSG msg;
ZeroMemory(&msg, sizeof(MSG));


//force create message queue
PeekMessage(&msg, NULL, WM_USER, WM_USER + 100, PM_NOREMOVE);

printf("Listing for clients on port %s \n", DEFAULT_PORT_STR);
while (listening) {
    // Accept a client socket
    ClientSocket = accept(ListenSocket, NULL, NULL);
    if (ClientSocket != INVALID_SOCKET) {
        printf("Client connected\n");

        sender = new SocketSender(ClientSocket);

        listener = new SocketListener(ClientSocket, this->m_threadId);
        printf("Listener created\n");

        listener->setSender(sender);
        listener->startThread();

        printf("Listener started\n");

        listenerList.push_back(listener);
        senderList.push_back(sender);

        printf("Listener list size: %d \n", listenerList.size());

        printf("Listener pushed to list\n");

        //delete socket data if listener close itself due to connection lost or disconnect.

    }
    else {
        int error = WSAGetLastError();
        printf("accept failed\n");
        switch (error) {
        case 10093:
            listening = false;
            try {
                closesocket(ListenSocket);
            }
            catch (...) {}
            return 1;
        }
    }

    printf("Check message queue for thread message\n");
    //check thread message queue
    //GetMessage(&msg, NULL, 0, 0); //this blocks untill a message is get.

    PeekMessage(&msg, NULL, WM_USER, WM_USER + 100, PM_REMOVE);



    if (msg.message == WM_USER + 1)
    {
        //ProcessCustomMessage(msg);
        m_deleteListener((SocketListener*)msg.wParam);
        printf("Recieved message from ThreadID: %d \n", msg.wParam);
    }
    printf("Recieved message from ThreadID: %d \n", msg.message);

    printf("Server socket complete 1 loop\n");
}

return 0;

}

DWORD SocketListener::m_ThreadFunc() {
listening = true;

rapidxml::xml_document<> doc;

printf("Start thread with ID: %d \n", this->m_threadId);
printf("Parent Thread ID: %d \n", this->_iParentID);


while (listening) {
    int iResult = recv(ClientSocket, recvbuf, recvbuflen, 0);
    if (iResult > 0) {
        printf("Bytes received: %d\n", iResult);
        recvbuf[iResult - 1] = 0; // null terminate the string according to the length

        // The message spec indicates the XML will end in a "new line"
        // character which can be either a newline or caraiage feed
        // Search for either and replace with a NULL to terminate
        if (recvbuf[iResult - 2] == '\n' || recvbuf[iResult - 2] == '\r')
            recvbuf[iResult - 2] = 0;

        try { 
            doc.parse<0>(&recvbuf[0]);
            HandleXMLMessage(&doc);
        }

        catch (...) {}

    }
    else {      
        printf("Thread %d is being closed, sending signal to parent (%d)\n", this->m_threadId, this->_iParentID);


        if (PostThreadMessage(this->_iParentID, WM_APP + 1, NULL, NULL) == 0)
        {
            printf("Client cant send Message before closing the conn ! \n");
            printf("Last error %d", GetLastError());
        }
        else {
            printf("Client sent Closing Message successfully \n");
        }


        closesocket(ClientSocket);
        return 1;
    }
}

printf("Server terminate connection\n");

printf("Thread %d is closed, sending signal to parent (%d)\n", this->m_threadId,this->_iParentID);

PostThreadMessage(this->_iParentID, WM_USER + 1, (WPARAM)this->m_threadId, NULL);


return 0;

}

非常感谢。

1 个答案:

答案 0 :(得分:0)

accept函数是一个阻塞调用,所以看起来在接受第一个连接后你的循环卡在

ClientSocket = accept(ListenSocket, NULL, NULL);

在下一次建立连接之前,不检查线程消息队列。

您还需要检查PeekMessage的返回结果,以了解消息是否实际被查看,否则msg变量将包含垃圾。