WinSock неблокирующий ввод / вывод

У меня есть WSASocket, который при подключении вызывает CreateProcess и серверы cmd.exe, я хотел реализовать канал между процессами hStdInput и Socket Handle для анализа команд, которые отправляются через сокет, кажется, что все работает гладко, за исключением случаев, когда я запустите команду типа «ping 127.0.0.1» и дождитесь вывода, ничего не отображается, пока я не отправлю больше данных через сокет, похоже, мой вызов ReadFile блокирует обработчик hStdOut от отправки чего-либо. Есть ли способ это исправить? Пожалуйста, не обижайтесь на мой код Я пишу этот проект как учебное упражнение, любая помощь будет оценена.

int syncShell(SOCKET *ConnectSocket) {
    int iResult = 0;
    printf("Spawning process
");
    char Process[] = "C:\Windows\System32\cmd.exe";
    STARTUPINFO sinfo;
    PROCESS_INFORMATION pinfo;
    memset(&sinfo, 0, sizeof(sinfo));
    sinfo.cb = sizeof(sinfo);
    sinfo.dwFlags = (STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW);

    // create pipe for external commands
    SECURITY_ATTRIBUTES  saAttr;
    saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); 
    saAttr.bInheritHandle = TRUE; 
    saAttr.lpSecurityDescriptor = NULL;
    HANDLE hReadPipe = NULL, hWritePipe = NULL;
    iResult = CreatePipe(&hReadPipe, &hWritePipe, &saAttr, DEFAULT_BUFLEN);
    if (iResult == 0) {
        printf("Pipe Error");
    }

    sinfo.hStdOutput = sinfo.hStdError = (HANDLE) *ConnectSocket;
    sinfo.hStdInput = hReadPipe;

    if (!CreateProcessA(NULL, Process, NULL, NULL, TRUE, 0, NULL, NULL, &sinfo, &pinfo)) {
        printf("CreateProcess failed (%d).
", GetLastError());
    }

    // implement pipe logic
    char buf[DEFAULT_BUFLEN];
    DWORD len = 0;
    WSABUF DataBuf;

    while (1) {
        // causing the block?
        iResult = ReadFile((HANDLE) *ConnectSocket, buf, DEFAULT_BUFLEN, &len, NULL);
        if (iResult == 0) {
            printf("File Error or non-blocking");
        }
        else {
            printf("%d: %.*s
", len, len, buf);
            WriteFile(hWritePipe, buf, len, NULL, NULL);
        }
        Sleep(1000);
    }

    WaitForSingleObject(pinfo.hProcess, INFINITE); // waits till proc finishes
    CloseHandle(pinfo.hProcess);
    CloseHandle(pinfo.hThread);
    printf("Process exited
");

    return 0;
}

Всего 1 ответ


Во-первых, согласно документу [ ReadFile ]:

Для асинхронных операций чтения hFile может быть любым дескриптором, который открывается с флагом CreateFile функцией CreateFile , или дескриптором сокета, возвращаемым функцией socket или accept .

socket создает дескриптор сокета с WSA_FLAG_OVERLAPPED по умолчанию. Вы получите код ошибки 87 ( ERROR_INVALID_PARAMETER ), если передадите перекрывающийся дескриптор и установите последний параметр ReadFile как NULL . Пример использования перекрытия:

OVERLAPPED oRead = { 0 };
oRead.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);  
iResult = ReadFile((HANDLE)ConnectSocket, buf, DEFAULT_BUFLEN, &len, &oRead);
if (!iResult && GetLastError() == ERROR_IO_PENDING)
{
    WaitForSingleObject(oRead.hEvent, INFINITE);
}
buf[oRead.InternalHigh] = 0;  //set string terminator for printf
printf("%s
", buf);
WriteFile(hWritePipe1, buf, oRead.InternalHigh, NULL, NULL);

И лучше использовать recv() напрямую:

iResult = recv(ConnectSocket, buf, DEFAULT_BUFLEN, 0);
buf[iResult] = 0;  //set string terminator for printf
printf("%s
", buf);
WriteFile(hWritePipe1, buf, iResult, NULL, NULL);

Кроме того, перекрывающийся сокет может использоваться для перенаправления ввода-вывода в дочерние процессы. Вы можете создать 2 канала для связи с дочерними процессами:

iResult = CreatePipe(&hReadPipe1, &hWritePipe1, &saAttr, DEFAULT_BUFLEN);
if (iResult == 0) {
    printf("Pipe Error");
}
iResult = CreatePipe(&hReadPipe2, &hWritePipe2, &saAttr, DEFAULT_BUFLEN);
if (iResult == 0) {
    printf("Pipe Error");
} 

Прочитать из дочернего процесса ( cmd.exe ) и отправить клиенту.

Или,

Просто используйте WSASocket вместо socket и НЕ указывайте WSA_FLAG_OVERLAPPED . (Рекомендуется)


Есть идеи?

10000