WinApi ReadFileEx & COMPLETION_ROUTINE
От: Alex76  
Дата: 19.10.19 13:09
Оценка:
Добрый день!
Помогите разобраться, не могу понять почему ядро вызывает 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()
{
    //StartSocketServerAPC();

    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

Re: WinApi ReadFileEx & COMPLETION_ROUTINE
От: reversecode google
Дата: 19.10.19 13:50
Оценка:
долго набирать
загуглите готовый пример и станет понятно
Re[2]: WinApi ReadFileEx & COMPLETION_ROUTINE
От: Alex76  
Дата: 20.10.19 10:52
Оценка:
Здравствуйте, reversecode, Вы писали:

R>долго набирать

R>загуглите готовый пример и станет понятно

3 дня гуглил, понятно не стало, поэтому и спрашиваю.
Просто если можно в двух словах, я ошибаюсь в понимании работы ReadFileEx или не сделал что то в колбэке?
Отредактировано 20.10.2019 11:02 Alex76 . Предыдущая версия .
Re[3]: WinApi ReadFileEx & COMPLETION_ROUTINE
От: reversecode google
Дата: 20.10.19 12:15
Оценка:
результат ReadFileEx выведите

впрочем
после dwNumberOfBytesTransfered == 0
соединение уже считается закрытым
и можно закрывать сокет

я не знаю что вы там гугли
но если не разбираетесь
возьмите какую нибудь готовую библиотеку
Отредактировано 20.10.2019 12:36 reversecode . Предыдущая версия .
Re[4]: WinApi ReadFileEx & COMPLETION_ROUTINE
От: Alex76  
Дата: 20.10.19 15:20
Оценка:
Здравствуйте, reversecode, Вы писали:

R>результат ReadFileEx выведите


R>впрочем

R>после dwNumberOfBytesTransfered == 0
R>соединение уже считается закрытым
R>и можно закрывать сокет

R>я не знаю что вы там гугли

R>но если не разбираетесь
R>возьмите какую нибудь готовую библиотеку


хм, возможно клиент действительно закрыл соединение, я про этот сценарий не подумал, пойду проверять
Отредактировано 20.10.2019 15:44 Alex76 . Предыдущая версия .
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.