[英]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.我有一个 WSASocket,当连接调用 CreateProcess 和服务器 cmd.exe 时,我想在进程 hStdInput 和套接字句柄之间实现一个管道来解析通过套接字发送的命令,除了当我运行像“ping 127.0.0.1”这样的命令并且必须等待输出,在我通过套接字发送更多数据之前没有任何显示,似乎我的 ReadFile 调用阻止了 hStdOut 处理程序发送任何内容。 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:首先,根据【
ReadFile
】文档:
For asynchronous read operations, hFile can be any handle that is opened with the
FILE_FLAG_OVERLAPPED
flag by theCreateFile
function, or a socket handle returned by thesocket
oraccept
function.对于异步读取操作,hFile 可以是
CreateFile
函数使用FILE_FLAG_OVERLAPPED
标志打开的任何句柄,或者是socket
或accept
函数返回的套接字句柄。
socket
create a socket handle with WSA_FLAG_OVERLAPPED
by default. socket
默认使用WSA_FLAG_OVERLAPPED
创建一个套接字句柄。 You will get error code 87( ERROR_INVALID_PARAMETER
) if you pass a Overlapped handle and set the last parameter of ReadFile
as NULL
.如果传递 Overlapped 句柄并将
ReadFile
的最后一个参数设置为NULL
则会得到错误代码 87( ERROR_INVALID_PARAMETER
)。 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:而且最好直接使用
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);
In addition, the overlapped socket could be used for redirected IO to child processes You could create 2 pipes to communicate with child process:此外,重叠套接字可用于将 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");
}
Read from child process( cmd.exe
), and send to client.从子进程(
cmd.exe
)读取,并发送到客户端。
Or,或者,
Just use WSASocket
instead of socket
, and do NOT specify the WSA_FLAG_OVERLAPPED
.(recommended)只需使用
WSASocket
而不是socket
,并且不要指定WSA_FLAG_OVERLAPPED
。(推荐)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.