如果没有先前的`WSARead`,`WSASend`永远不会触发完成例程

时间:2017-10-27 11:29:59

标签: windows c++11 winsock2 io-completion-ports

我正在开发管理req / res主题的服务器 - 客户端应用程序,并对某些消息进行扇出。消息以重叠模式与WSASend一起发送,并提供完成例程。注意到WSASend触发发件人完成例程后,WSARead下一次发送。虽然在WSARead之前的服务器发送的发送没有触发完成例程。为什么会这样?

bool CCommunicationServer::ManageReadMessage(UCHAR index)
{
    OVERLAPPED_EX *over = m_readov[index];
    DWORD bytes = 0, flags = 0;

    if (WSARecv(over->socket, &(over->wsabuf), 1, &bytes, &flags, over, &CCommunicationServer::WorkerReadRoutine) == SOCKET_ERROR) {
        bytes = WSAGetLastError();

        if (bytes != WSA_IO_PENDING) {
            LOG(ERROR) << std::endl << "WSARecv() failed w/err " << bytes;
            shutdown(m_readov[index]->socket, SD_BOTH);
            return FALSE;
        }
    }

    return TRUE;
}

bool CCommunicationServer::ManageSendMessage(UCHAR index, char* msg, OVERLAPPED_EX *moreover)
{
    OVERLAPPED_EX *over = moreover;
    DWORD bytes = 0;
    SOCKET socket = m_readov[index] != NULL ? m_readov[index]->socket : NULL;

    if (!over) {
        ScopedLock lock(&m_lock);

        if (!msg) {
            LOG(WARNING) << "Empty send! Ignoring!";
            return FALSE;
        } else if (m_readov[index] != NULL) {
            LOG(DEBUG) << ++created << "\t:\t" << deleted << "\t\t\t\r";
            over = new OVERLAPPED_EX(this, m_readov[index]->socket, index, msg);
        } else {
            return FALSE;
        }
    }

    if (WSASend(socket, &(over->wsabuf), 1, &bytes, 0, (LPWSAOVERLAPPED)over, &CCommunicationServer::WorkerSendRoutine) == SOCKET_ERROR) {
        bytes = bytes = WSAGetLastError();

        if (bytes != WSA_IO_PENDING) {
            LOG(ERROR) << std::endl << "WSASend() failed w/err " << bytes;
            shutdown(socket, SD_BOTH);
            LOG(DEBUG) << created << "\t:\t" << ++deleted << "\t\t\t\r";
            delete over;
            return FALSE;
        }
    }

    return TRUE;
}

以下是完成例程:

void CALLBACK CCommunicationServer::WorkerReadRoutine(DWORD Error, DWORD BytesTransferred, LPWSAOVERLAPPED Overlapped, DWORD InFlags)
{
    OVERLAPPED_EX *over = (OVERLAPPED_EX*)Overlapped;

    if (Error)
        return;

    if (BytesTransferred > 0) {
        over->server->GetRequest(over);
    }

    over->server->ManageReadMessage(over->index);
}

void CALLBACK CCommunicationServer::WorkerSendRoutine(DWORD Error, DWORD BytesTransferred, LPWSAOVERLAPPED Overlapped, DWORD InFlags)
{
    OVERLAPPED_EX *over = (OVERLAPPED_EX*)Overlapped;

    if (Error || over->wsabuf.len == BytesTransferred) {
        LOG(DEBUG) << over->server->created << "\t:\t" << ++over->server->deleted << "\t\t\t\r";
        delete over;
    } else {
        over->wsabuf.buf += BytesTransferred;
        over->wsabuf.len -= BytesTransferred;
        over->server->ManageSendMessage(over->index, NULL, over);
    }
}

变量createddeleted显示创建了多少OVERLAPPED_EX个结构,然后释放以避免内存泄漏。

0 个答案:

没有答案