Winsock RIO: RIOReceive возвращается немедленно без передачи байтов

У меня проблемы с работой Winsock RIO. Кажется, что каждый раз, когда я отправляю RIOReceive, он немедленно возвращается с 0 переданными байтами, и мой партнер не может передать сообщение.

После публикации RIOReceive я жду RIODequeCompletion, который немедленно удаляется с numResults = 1, но когда я проверяю bytesTransferred структуры RIORESULT, это 0. Это говорит мне, что я не настраиваю эту вещь должным образом, но я могу Я не могу найти документы или примеры, которые говорят мне, что еще мне следует делать.

Похоже, что в Интернете очень мало информации о РИО. Я просмотрел MSDN, Лен Холгейт с TheServerFramework, этим сайтом и двумя серверами GitHub RIO.

RIOEchoServer и RIOServer_sm9 находятся на GitHub, но я не могу разместить более двух ссылок (это мой первый вопрос на этом сайте).

Этот код предназначен только для проверки. В настоящее время он не настроен на использование sendCQ, плохо обрабатывает ошибки и т. Д.

Вот подготовительная работа:

void serverRequestThread() {

//init buffers 

//register big buffers
recvBufferMain = rio.RIORegisterBuffer(pRecvBufferMain, bufferSize);
sendBufferMain = rio.RIORegisterBuffer(pSendBufferMain, bufferSize);

if (recvBufferMain == RIO_INVALID_BUFFERID) {
    cout << "RIO_INVALID_BUFFERID" << endl;
}

if (sendBufferMain == RIO_INVALID_BUFFERID) {
    cout << "RIO_INVALID_BUFFERID" << endl;
}

//create recv buffer slice
recvBuffer1.BufferId = recvBufferMain;
recvBuffer1.Offset = 0;
recvBuffer1.Length = 10000;

//create send buffer slice
sendBuffer1.BufferId = sendBufferMain;
sendBuffer1.Offset = 0;
sendBuffer1.Length = 10000;

//completion queue
recvCQ = rio.RIOCreateCompletionQueue(CQsize, NULL);
sendCQ = rio.RIOCreateCompletionQueue(CQsize, NULL);

if (recvCQ == RIO_INVALID_CQ) {
    cout << "RIO_INVALID_CQ" << endl;
}

if (sendCQ == RIO_INVALID_CQ) {
    cout << "RIO_INVALID_CQ" << endl;
}

//start a loop for newly accept'd socket
while (recvCQ != RIO_INVALID_CQ && sendCQ != RIO_INVALID_CQ) {

    //get accept'd socket
    struct sockaddr_in saClient;
    int iClientSize = sizeof(saClient);
    acceptSocket = accept(listenSocket, (SOCKADDR*)&saClient, &iClientSize);

    if (acceptSocket == INVALID_SOCKET) {
        cout << "Invalid socket" << endl;
        printError();
    }

    //register request queue
    requestQueue = rio.RIOCreateRequestQueue(
        acceptSocket,       //socket
        10,                 //max RECVs on queue
        1,                  //max recv buffers, set to 1
        10,                 //max outstanding sends
        1,                  //max send buffers, set to 1
        recvCQ,             //recv queue
        recvCQ,             //send queue
        pOperationContext   //socket context
        );

    if (requestQueue == RIO_INVALID_RQ) {
        cout << "RIO_INVALID_RQ" << endl;
        printError();
    }

Я сейчас отправляю RIOReceive:

    //start a loop to repin recv buffer for socket
    while (acceptSocket != INVALID_SOCKET) {

        //pin a recv buffer to wait on data
        recvSuccess = rio.RIOReceive(
            requestQueue,           //socketQueue
            &recvBuffer1,           //buffer slice
            1,                      //set to 1
            RIO_MSG_WAITALL,                        //flags
            0);                     //requestContext

        if (recvSuccess == false) {
            cout << "RECV ERROR!!!!!!!!\n";
            printError();
        }

        //wait for recv to post in queue

        //std::this_thread::sleep_for(std::chrono::milliseconds(3000));

Как только я вызываю RIODequeCompletion, он возвращает 1:

        numResults = 0;
        while (numResults == 0) numResults = rio.RIODequeueCompletion(recvCQ, recvArray, 10);

        if (numResults == RIO_CORRUPT_CQ) {

            cout << "RIO_CORRUPT_CQ" << endl;

        } else if (numResults == 0) {

            cout << "no messages on queue\n";

        } else if (numResults > 0) {

но когда я проверяю bytesTransferred RIORESULT, всегда 0:

            if (recvArray[0].BytesTransferred > 0) {

                //process results
                if (pRecvBufferMain[0] == 'G') {

                    //set respnose html
                    strcpy(pSendBufferMain, responseHTTP);

                    sendSuccess = rio.RIOSend(
                        requestQueue,   //socketQueue
                        &sendBuffer1,   //buffer slice
                        1,              //set to 1
                        0,              //flags
                        0);             //requestContext

                } else if (pRecvBufferMain[0] == 'P') {

                    //process post 


                } else {
                    //recv'd a bad message

                }

            } //end bytesTransferred if statement

            //reset everything and post another recv

        }//end response if statement

        std::this_thread::sleep_for(std::chrono::milliseconds(100));

    }//end while loop for recv'ing

    std::this_thread::sleep_for(std::chrono::milliseconds(100));

}//end while loop for accept'ing

}// end function

Как я уже сказал, я, вероятно, неправильно использую RIOReceive и / или я не устанавливаю правильные параметры сокета, которые мне нужны (сейчас их нет).

Я ценю любую помощь с этим.


person Michael220    schedule 05.02.2015    source источник
comment
Почему вы в первую очередь используете RIO вместо традиционного ввода-вывода сокетов, или перекрывающихся портов ввода-вывода или портов завершения ввода-вывода? Почему вы опрашиваете очереди RIO вместо того, чтобы получать уведомления о готовности? И вы используете recvCQ для очередей отправки и получения в RIOCreateRequestQueue(), вы не используете sendCQ для очереди отправки.   -  person Remy Lebeau    schedule 05.02.2015
comment
Я просто смотрю в RIO, чтобы узнать, подходит ли он для моего сервера. Как вы знаете, опрос неэффективен, но при большой нагрузке он обеспечивает наивысшую производительность, поскольку IOCP потребляет циклы. Кроме того, это самый простой способ, поэтому я использую его здесь, чтобы получить некоторые числа на доске. Да, sendCQ не подключен. Я временно удалил его для отладки, но он вернется. Спасибо за вопрос ... У вас есть идеи, почему я не получаю байты из RIOReceive / RIODequeueCompletion / RIORESULT?   -  person Michael220    schedule 05.02.2015
comment
Я никогда раньше не пользовался РИО. IOCP всегда был предпочтительным высокопроизводительным решением. Я не знаю, почему MS почувствовала необходимость представить еще один API сокетов, когда у них уже есть несколько. В любом случае полученный результат 0 байтов обычно указывает на то, что сокет был закрыт партнером.   -  person Remy Lebeau    schedule 06.02.2015
comment
Однако я не получаю ошибок WSAENETRESET или WSAENOTCONN. Можно ли по-прежнему иметь разорванное / отключенное соединение без этих ошибок?   -  person Michael220    schedule 06.02.2015
comment
@RemyLebeau: Поскольку проблема C10K возникла вчера, мы сейчас находимся в области проблем C100K или даже C1M. Вы можете получить серверы с пропускной способностью 40 ГБит уже сейчас. Каждый цикл может иметь значение, и да, RIO работает быстрее. Скоро мы увидим полный стек Ethernet пользовательского уровня. API-интерфейс Berkley 1970 года и IOCP, которому уже 20 лет, - это не будущее.   -  person Lothar    schedule 28.11.2015


Ответы (2)


Попробуйте удалить RIO_MSG_WAITALL. Может быть ошибка, из-за которой вы получаете только уведомление о закрытии (байты == 0), а не получаете завершение с данными в нем. В любом случае было бы интересно посмотреть, работает ли код без флага.

Работают ли мои примеры серверов и тестов на вашем оборудовании?

person Len Holgate    schedule 07.02.2015
comment
Спасибо, Лен. Это было одним из факторов, которые способствовали этому. После того, как я удалил это, я также обнаружил, что я неправильно определил размер своего CQ, чтобы он был достаточно большим для всех моих RQ. Я прочитал все ваши блоги, они мне очень помогли, но я еще не запускал код. Я сосредоточился на TCP и подумал, что могу просто изучить теорию и построить простой сервер. Реальность, конечно, была другой, поэтому я могу вернуться и запустить ваш UDP-сервер / клиентов и продолжить работу оттуда. Спасибо, что поделились своей работой! - person Michael220; 10.02.2015
comment
Причина, по которой я спросил о моих тестах, работающих на вашем оборудовании, заключалась в том, что у меня были клиенты, у которых на разных машинах были установлены странные вещи, и, по-видимому, это повлияло на RIO. Так что хорошо сначала получить базовый пример, который, как известно, работает. Рад, что ты нашел проблему. Возникает проблема с повреждением CQ, если вы отправляете больше запросов (и они выполняются), чем в CQ есть место; так что вы должны быть осторожны с этим. - person Len Holgate; 10.02.2015

Я столкнулся с аналогичной проблемой с нулевым получением байтов в моем исключенном результате завершения при использовании RioReceive с RioNotify и RioDequeueCompletion. Я бы также увидел значение «Статус» WSAEINVAL (Invalid Parameter = 10022) в моем исключенном из очереди результате завершения, это, похоже, указывает на код ошибки WSA для вызова приема.

Конкретная причина, по которой у меня возникла ошибка, заключается в том, что я выделил память для receiveBuffer, и я пытался передать этот указатель буфера в качестве дескриптора буфера в RIO_BUFFER_SEGMENT, переданном RioReceive вместо передачи IntPtr возвращается RioRegisterBuffer.

Я полностью виню себя в том, что использую слишком много нетипизированных IntPtr и теряю проверку типов. :)

person Tim Lovell-Smith    schedule 06.10.2015