簡體   English   中英

WinSock 非阻塞 I/O

[英]WinSock Non-Blocking I/O

我有一個 WSASocket,當連接調用 CreateProcess 和服務器 cmd.exe 時,我想在進程 hStdInput 和套接字句柄之間實現一個管道來解析通過套接字發送的命令,除了當我運行像“ping 127.0.0.1”這樣的命令並且必須等待輸出,在我通過套接字發送更多數據之前沒有任何顯示,似乎我的 ReadFile 調用阻止了 hStdOut 處理程序發送任何內容。 有沒有什么辦法解決這一問題? 請不要被我的代碼冒犯我正在編寫這個項目作為學習練習,任何幫助將不勝感激。

int syncShell(SOCKET *ConnectSocket) {
    int iResult = 0;
    printf("Spawning process\n");
    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).\n", 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\n", 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\n");

    return 0;
}

首先,根據【 ReadFile 】文檔:

對於異步讀取操作,hFile 可以是CreateFile函數使用FILE_FLAG_OVERLAPPED標志打開的任何句柄,或者是socketaccept函數返回的套接字句柄。

socket默認使用WSA_FLAG_OVERLAPPED創建一個套接字句柄。 如果傳遞 Overlapped 句柄並將ReadFile的最后一個參數設置為NULL則會得到錯誤代碼 87( ERROR_INVALID_PARAMETER )。 使用重疊的示例:

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\n", 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\n", buf);
WriteFile(hWritePipe1, buf, iResult, NULL, NULL);

此外,重疊套接字可用於將 IO 重定向到子進程您可以創建 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 。(推薦)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM