我目前正在用托管C ++编写Winsock服务器端套接字。创建LPWSAOVERLAPPED对象并将其传递给WSASend函数之后,当操作完成非阻塞操作时(WSASend返回SOCKET_ERROR,而WSAGetLastError()返回WSA_IO_PENDING),我看不到在哪里删除该对象。我当前的解决方案是创建一个System :: Threading :: WaitHandle,获取指向等待句柄的不安全指针,并将其传递给LPWSAOVERLAPPED对象下的hEvent。但是,这导致不必要的对象创建,因为我并不真正在乎发送操作何时完成。另一方面,我需要一个LPWSAOVERLAPPED对象,以使操作完全无阻塞。有谁有更好的解决方案来解决这个问题?这是我当前的代码:

void Connectivity::ConnectionInformation::SendData(unsigned char data[], const int length)
{
    if (isClosed || sendError)
        return;

    Monitor::Enter(this->sendSyncRoot);
    try
    {
        LPWSAOVERLAPPED overlapped = OverlappedObjectPool::GetOverlapped();
        WaitHandle ^ handle = gcnew ManualResetEvent(false);
        IntPtr handlePointer = handle->SafeWaitHandle->DangerousGetHandle();

        sendInfo->buf = (char*)data;
        sendInfo->len = length;

        overlapped->Internal = 0;
        overlapped->InternalHigh = 0;
        overlapped->Offset = 0;
        overlapped->OffsetHigh = 0;
        overlapped->Pointer = 0;
        overlapped->hEvent = (void*)handlePointer;                      //Set pointer

        if (WSASend(connection, sendInfo, 1, NULL, 0, overlapped, NULL) == SOCKET_ERROR)
        {
            if (WSAGetLastError() == WSA_IO_PENDING)
            {
                ThreadPool::UnsafeRegisterWaitForSingleObject(handle, sentCallback, (IntPtr)((void*)overlapped), -1, true);
            }
            else
            {
                this->sendError = true;
                //The send error bool makes sure that the close function doesn't get called
                //during packet processing which could lead to a lot of null reffernce exceptions.
                OverlappedObjectPool::GiveObject(overlapped);
            }
        }
        else
        {
            handle->Close();
            sentData((IntPtr)((void*)overlapped), false);
        }
    }
    finally
    {
        Monitor::Exit(this->sendSyncRoot);
    }
}

最佳答案

对于异步I / O,可通过调用完成例程或将IOCP完成消息排队到IOCP完成队列来通知完成。在这两种情况下,都应注意,OVL结构的生存期至少应为整个异步操作的寿命,但如果方便的话,可以更长一些:)

在完成例程的情况下,OVL中未使用的hEvent参数可用于将指针转移到“ IOrequest”类实例,该实例包含一个或多个数据缓冲区,WSABUF数组和OVL结构作为成员(当然,指向已为其发出I / O的套接字对象的指针)。 OVL指针作为完成例程的参数提供,因此可以检索hEvent并将其转换为类类型,从而检索完整的类实例-OVL,数据缓冲区等。处理完数据后,(或立即在(例如WSASend的完成例程),并且此IOrequest最终被销毁(或回收),OVL将随之处理。这听起来有点乱伦,但效果很好,不需要任何讨厌的宏或其他技巧。

完整的IOCP可以使用类似的方法,也可以将OVL作为lpCompletionKey'spare'参数传递。

哦-而且您确实要注意操作是否完成-您至少需要检查是否有错误。

关于c++ - WSASend之后处理LPWSAOVERLAPPED,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/14042734/

10-12 22:33