简体   繁体   中英

WinSock Non-Blocking I/O

I have a WSASocket which when connected calls CreateProcess and servers cmd.exe, I wanted to implement a pipe in-between the processes hStdInput and the Socket Handle to parse commands that get sent over the socket, everything seems to run smoothly except for when I run a command like "ping 127.0.0.1" and have to wait for output, nothing shows up until I send more data over the socket, it seems my ReadFile call is blocking hStdOut handler from sending anything. Is there any way to fix this? Please don't be offended by my code I'm writing this project as a learning exercise, any help would be appreciated.

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;
}

First, according to the [ ReadFile ] document:

For asynchronous read operations, hFile can be any handle that is opened with the FILE_FLAG_OVERLAPPED flag by the CreateFile function, or a socket handle returned by the socket or accept function.

socket create a socket handle with WSA_FLAG_OVERLAPPED by default. You will get error code 87( ERROR_INVALID_PARAMETER ) if you pass a Overlapped handle and set the last parameter of ReadFile as NULL . Sample to use Overlapped:

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);

And it's better to use recv() directly:

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);

In addition, the overlapped socket could be used for redirected IO to child processes You could create 2 pipes to communicate with child process:

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");
} 

Read from child process( cmd.exe ), and send to client.

Or,

Just use WSASocket instead of socket , and do NOT specify the WSA_FLAG_OVERLAPPED .(recommended)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM