RIOSendEx получает ошибку 10022, но connect + RIOSend работает хорошо - PullRequest
0 голосов
/ 14 декабря 2018

Я изучаю Windows Registered I / O, я нашел пример проекта с веб-сайта "https://github.com/zeliard/RIOEchoServer", Он хорошо работает на моем компьютере.

Однако, если я изменю этот код сслушая серверную сторону активно отправляющей клиентской стороны, я обнаружил, что connect + RIOSend работает нормально, но RIOSendEx определенно выдаст код ошибки 10022!

#include <WinSock2.h>
#include <MSWsock.h>
#include <WS2tcpip.h>
#include <stdio.h>

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

int main(int argc, char * argv[])
{
    static const wchar_t SERVER[] = L"127.0.0.1";
    static const unsigned short PORTNUM = 54321;
    static const DWORD RIO_PENDING_RECVS = 1;
    static const DWORD RIO_PENDING_SENDS = 1;
    static const DWORD RECV_BUFFER_SIZE = 1024;
    static const DWORD SEND_BUFFER_SIZE = 1024;
    static const DWORD ADDR_BUFFER_SIZE = 64;
    static const DWORD RIO_MAX_RESULTS = 1;

    WSADATA wsadata;
    if (0 != ::WSAStartup(0x202, &wsadata))
    {
        printf_s("WSAStartup Error: %d\n", GetLastError());
        exit(0);
    }

    /// RIO socket
    SOCKET socket = WSASocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP, NULL, 0, WSA_FLAG_REGISTERED_IO);
    if (socket == INVALID_SOCKET)
    {
        printf_s("WSASocket Error: %d\n", GetLastError());
        exit(0);
    }

    /// RIO function table
    GUID functionTableId = WSAID_MULTIPLE_RIO;
    DWORD dwBytes = 0;
    RIO_EXTENSION_FUNCTION_TABLE rio;
    if (NULL != WSAIoctl(socket, SIO_GET_MULTIPLE_EXTENSION_FUNCTION_POINTER, &functionTableId, sizeof(GUID), (void**)&rio, sizeof(rio), &dwBytes, NULL, NULL))
    {
        printf_s("WSAIoctl Error: %d\n", GetLastError());
        exit(0);
    }

    /// rio's completion manner: iocp
    HANDLE hIOCP = ::CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0, 0);
    if (NULL == hIOCP)
    {
        printf_s("CreateIoCompletionPort Error: %d\n", GetLastError());
        exit(0);
    }


    OVERLAPPED overlapped;
    RIO_NOTIFICATION_COMPLETION completionType;
    completionType.Type = RIO_IOCP_COMPLETION;
    completionType.Iocp.IocpHandle = hIOCP;
    completionType.Iocp.CompletionKey = NULL;
    completionType.Iocp.Overlapped = &overlapped;

    /// creating RIO CQ, which is bigger than (or equal to) RQ size
    RIO_CQ completionQueue = rio.RIOCreateCompletionQueue(RIO_PENDING_RECVS + RIO_PENDING_SENDS, &completionType);
    if (completionQueue == RIO_INVALID_CQ)
    {
        printf_s("RIOCreateCompletionQueue Error: %d\n", GetLastError());
        exit(0);
    }

    /// creating RIO RQ
    /// SEND and RECV within one CQ (you can do with two CQs, seperately)
    RIO_RQ requestQueue = rio.RIOCreateRequestQueue(socket, RIO_PENDING_RECVS, 1, RIO_PENDING_SENDS, 1, completionQueue, completionQueue, NULL);
    if (requestQueue == RIO_INVALID_RQ)
    {
        printf_s("RIOCreateRequestQueue Error: %d\n", GetLastError());
        exit(0);
    }


    /// registering RIO buffers for SEND
    char sendBuffer[SEND_BUFFER_SIZE];
    RIO_BUFFERID sendRioBufferId = rio.RIORegisterBuffer(sendBuffer, static_cast<DWORD>(sizeof(sendBuffer)));
    if (sendRioBufferId == RIO_INVALID_BUFFERID)
    {
        printf_s("RIORegisterBuffer Error: %d\n", GetLastError());
        exit(0);
    }
    RIO_BUF sendRioBuffer;
    sendRioBuffer.BufferId = sendRioBufferId;
    sendRioBuffer.Offset = 0;
    sendRioBuffer.Length = SEND_BUFFER_SIZE;


    /// registering RIO buffers for ADDR
    char addrBuffer[ADDR_BUFFER_SIZE];
    RIO_BUFFERID addrRioBufferId = rio.RIORegisterBuffer(addrBuffer, static_cast<DWORD>(sizeof(addrBuffer)));
    if (addrRioBufferId == RIO_INVALID_BUFFERID)
    {
        printf_s("RIORegisterBuffer Error: %d\n", GetLastError());
        exit(0);
    }
    RIO_BUF addrRioBuffer;
    addrRioBuffer.BufferId = addrRioBufferId;
    addrRioBuffer.Offset = 0;
    addrRioBuffer.Length = ADDR_BUFFER_SIZE;


    /// registering RIO buffers for RECV and then, post pre-RECV
    char recvBuffer[RECV_BUFFER_SIZE];
    RIO_BUFFERID recvRioBufferId = rio.RIORegisterBuffer(recvBuffer, static_cast<DWORD>(sizeof(recvBuffer)));
    if (recvRioBufferId == RIO_INVALID_BUFFERID)
    {
        printf_s("RIORegisterBuffer Error: %d\n", GetLastError());
        exit(0);
    }
    RIO_BUF recvRioBuffer;
    recvRioBuffer.BufferId = recvRioBufferId;
    recvRioBuffer.Offset = 0;
    recvRioBuffer.Length = RECV_BUFFER_SIZE;

    /// posting pre RECVs
    if (!rio.RIOReceiveEx(requestQueue, &recvRioBuffer, 1, NULL, &addrRioBuffer, NULL, 0, 0, &recvRioBuffer))
    {
        printf_s("RIOReceive Error: %d\n", GetLastError());
        exit(0);
    }


    //////////////////////////////////////////////////////////////////////////
    // active send code begin ...
    //////////////////////////////////////////////////////////////////////////

    sendRioBuffer.Length = 5;
    memcpy_s(sendBuffer, RECV_BUFFER_SIZE, "hello", sendRioBuffer.Length);

    sockaddr_in * address = reinterpret_cast<sockaddr_in *>(addrBuffer);
    memset(address, 0x0, ADDR_BUFFER_SIZE);
    address->sin_family = AF_INET;
    address->sin_port = htons(PORTNUM);
    if (::InetPton(AF_INET, SERVER, &address->sin_addr) <= 0)
    {
        printf_s("inet_pton Error: %d\n", GetLastError());
        exit(0);
    }

#if 0 // connect + RIOSend is OK

    if (SOCKET_ERROR == ::connect(socket, reinterpret_cast<struct sockaddr *>(address), sizeof(*address)))
    {
        printf_s("Connect Error: %d\n", GetLastError());
        exit(0);
    }

    if (!rio.RIOSend(requestQueue, &sendRioBuffer, 1, 0, &sendRioBuffer))
    {
        printf_s("RIOSend Error: %d\n", GetLastError());
        exit(0);
    }

#else // RIOSendEx not work

    if (!rio.RIOSendEx(requestQueue, &sendRioBuffer, 1, NULL, &addrRioBuffer, NULL, NULL, 0, &sendRioBuffer))
    {
        printf_s("RIOSendEx Error: %d\n", GetLastError());
        exit(0);
    }

#endif // 0

    INT notifyResult = rio.RIONotify(completionQueue);
    if (notifyResult != ERROR_SUCCESS)
    {
        printf_s("RIONotify Error: %d\n", GetLastError());
        exit(0);
    }

    DWORD numberOfBytes = 0;
    ULONG_PTR completionKey = 0;
    OVERLAPPED* pOverlapped = 0;
    RIORESULT results[RIO_MAX_RESULTS];
    if (!::GetQueuedCompletionStatus(hIOCP, &numberOfBytes, &completionKey, &pOverlapped, INFINITE))
    {
        printf_s("GetQueuedCompletionStatus Error: %d\n", GetLastError());
        exit(0);
    }

    memset(results, 0, sizeof(results));

    ULONG numResults = rio.RIODequeueCompletion(completionQueue, results, RIO_MAX_RESULTS);
    if (0 == numResults || RIO_CORRUPT_CQ == numResults)
    {
        printf_s("RIODequeueCompletion Error: %d\n", GetLastError());
        exit(0);
    }

    const RIORESULT & res = results[0];
    if (0 != res.Status)
    {
        printf_s("RIOSend(Ex) Error: %d\n", res.Status);
        exit(0);
    }

    printf_s("RIOSend(Ex) OK\n");

    //////////////////////////////////////////////////////////////////////////
    // active send code end ...
    //////////////////////////////////////////////////////////////////////////

    if (SOCKET_ERROR == ::closesocket(socket))
    {
        printf_s("closesocket Error: %d\n", GetLastError());
    }

    rio.RIOCloseCompletionQueue(completionQueue);

    rio.RIODeregisterBuffer(sendRioBufferId);
    rio.RIODeregisterBuffer(recvRioBufferId);
    rio.RIODeregisterBuffer(addrRioBufferId);

    return 0;
}

желаю вашей помощиСпасибо!

yanrk

Ответы [ 2 ]

0 голосов
/ 16 августа 2019

Вы не установили IP-адрес назначения в RioSendEx-Function: скопируйте содержимое вашего адресного буфера в соответствующий буфер addrRioBuffer.

например:

memcpy_s(addrBuffer, ADDR_BUFFER_SIZE, address, sizeof(sockaddr_in));

if (!rio.RIOSendEx(requestQueue, &sendRioBuffer, 1, NULL, &addrRioBuffer, NULL, NULL, 0, &sendRioBuffer))
    {
        printf_s("RIOSendEx Error: %d\n", GetLastError());
        exit(0);
    }
// […]

Я опубликую рабочий экзамен на следующий день.http://www.thbweb.eu

0 голосов
/ 11 марта 2019

connect + RIOSendEx не имеет смысла.Так как вы указали удаленный адрес с помощью функции подключения, вы не можете отправлять данные через этот сокет где-либо еще.Предполагается, что RIOSendEx будет использоваться с дейтаграммами.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...