WinApi ReadFileEx & COMPLETION_ROUTINE

79
24 сентября 2021, 18:20

Помогите разобраться, не могу понять почему ядро вызывает COMPLETION_ROUTINE не дожидаясь новых данных в сокете?

Последовательность действий такая, листенер ожидает соединения, после соединения акцепт возвращает сокет, для этого сокета вызывается асинхронная ReadFileEx, дальше поток становится в ожидание в тревожном состоянии(alertable wait state — вызов SleepEx(INFINITE, true)).
Дальше поведение предсказуемо, когда в сокет поступают данные, ядро через APC, ставит в очередь IRP, поток просыпается и срабатывает CompletionRoutineReadfileex2, в котором читаем данные. Потом снова ставим для сокета ReadFileEx что бы ждать новых данных и тут или я не правильно понимаю принцип работы или надо сделать что то еще, но ядро вызывает колбэк(CompletionRoutineReadfileex2) сразу, не дожидаясь новых данных в сокете, тоесть приходит dwNumberOfBytesTransfered = 0 и так бесконечно.
По моему разумению, поток должен выйти и проснуться только тогда, когда будут новые данные. То есть, в COMPLETION_ROUTINE(CompletionRoutineReadfileex2) не происходит обнуление чего то и ядро считает что я не прочитал данные и снова вызывает колбэк. CancelIo пробовал, не помогло.

#include "pch.h"
#include <iostream>
#include "SocketServerAPC01.h"
char sock_in_buf2[256];
int byte_available2;
void CALLBACK CompletionRoutineReadfileex2(DWORD dwErrorCode, DWORD dwNumberOfBytesTransfered, LPOVERLAPPED lpOverlapped)
{
    byte_available2 = dwNumberOfBytesTransfered;
    cout << "CompletionRoutineReadfileex ->> " << dwNumberOfBytesTransfered << " dwErrorCode ->" << dwErrorCode << endl;
    Sleep(300);
    ovpConnection *ov2 = (ovpConnection*)lpOverlapped;
    memset(sock_in_buf2, 0, sizeof(sock_in_buf2));
    unsigned long bw;
    ovpConnection *ov3 = new ovpConnection;
    memset(ov3, 0, sizeof(*ov3));
    ov3->sock_handle = ov2->sock_handle;
    ReadFileEx((HANDLE)ov3->sock_handle, sock_in_buf2, sizeof(sock_in_buf2), ov3, (LPOVERLAPPED_COMPLETION_ROUTINE)CompletionRoutineReadfileex2);
}

int main()
{
    int err;                 
    char buffer[128];   
    WORD wVersionRequested;  
    WSADATA wsaData;         
    SOCKET listen_socket;
    LPFN_ACCEPTEX lpfn_accept;

    wVersionRequested = MAKEWORD(2, 2);
    err = WSAStartup(wVersionRequested, &wsaData);
    if (err == SOCKET_ERROR)
    {
        strcpy_s(buffer, "Function error WSAStartup");
        printf("%s %d\n", buffer, WSAGetLastError());
        WSACleanup(); 
        return 1;
    }
    listen_socket = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, NULL, WSA_FLAG_OVERLAPPED);
    SOCKADDR_IN sinServer;
    sinServer.sin_family = AF_INET;
    sinServer.sin_port = htons(PORT);
    sinServer.sin_addr.s_addr = INADDR_ANY;
    err = bind(listen_socket, (LPSOCKADDR)&sinServer, sizeof(sinServer));
    if (err == -1)
    {
        strcpy_s(buffer, "Function error bind");
        printf("%s %d\n", buffer, GetLastError());
        WSACleanup();
        return 1;
    }
    err = listen(listen_socket, SOMAXCONN);
    if (err == -1)
    {
        strcpy_s(buffer, "Function error listen №");
        printf("%s %d\n", buffer, GetLastError());
        WSACleanup(); 
        return 1;
    }

    SOCKET accept_socket = accept(listen_socket, NULL, NULL);
    ovpConnection *ov2 = new ovpConnection;
    memset(ov2, 0, sizeof(*ov2));
    ov2->sock_handle = accept_socket;
    ReadFileEx((HANDLE)accept_socket, sock_in_buf2, sizeof(sock_in_buf2), ov2, (LPOVERLAPPED_COMPLETION_ROUTINE)CompletionRoutineReadfileex2);
    DWORD dwWait;
    HANDLE hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
    std::cout << "Hello World!\n";
    while (1) {
        dwWait = SleepEx(INFINITE, true);
        //dwWait = WaitForSingleObjectEx(hEvent, INFINITE, TRUE);
        cout << "dwWait -> " << dwWait << endl;
    }
    return 0;
}

вывод на консоль:

CompletionRoutineReadfileex ->> 6 dwErrorCode ->0
dwWait -> 192
CompletionRoutineReadfileex ->> 0 dwErrorCode ->0
CompletionRoutineReadfileex ->> 0 dwErrorCode ->0
CompletionRoutineReadfileex ->> 0 dwErrorCode ->0
CompletionRoutineReadfileex ->> 0 dwErrorCode ->0
CompletionRoutineReadfileex ->> 0 dwErrorCode ->0
CompletionRoutineReadfileex ->> 0 dwErrorCode ->0
CompletionRoutineReadfileex ->> 0 dwErrorCode ->0
CompletionRoutineReadfileex ->> 0 dwErrorCode ->0
CompletionRoutineReadfileex ->> 0 dwErrorCode ->0
CompletionRoutineReadfileex ->> 0 dwErrorCode ->0
CompletionRoutineReadfileex ->> 0 dwErrorCode ->0
CompletionRoutineReadfileex ->> 0 dwErrorCode ->0
CompletionRoutineReadfileex ->> 0 dwErrorCode ->0
CompletionRoutineReadfileex ->> 0 dwErrorCode ->0
READ ALSO
define для нескольких слов

define для нескольких слов

Можно ли с помощью директивы #define заменить не одно слово на другое, а сразу кусок текста на другой кусок?

144
C++, идиома Opaque Pointer и паттерн Стратегия

C++, идиома Opaque Pointer и паттерн Стратегия

Подскажите, пожалуйста, возможно ли в C++ следующее:

75
Автовоспроизвидение видео в Ios Safari

Автовоспроизвидение видео в Ios Safari

Делаю стриминг сервис для вебинаровКогда пользователь заходит на страницу, он видит таймер и когда таймер подходит к концу - мне надо запустить...

96
Не работают кнопки слайдера

Не работают кнопки слайдера

Хотел сделать, чтобы при нажатии на стрелки класс -active переходил к предыдущей, либо к следующей кнопке slider__btnИ при нажатии на не активную кнопку...

76