cmd.exe
下运行良好,每几秒钟打印一次新行。当我使用下面的代码时,在SO上讨论了很多次,
ReadFile
函数不会返回,直到该程序停止。然后由ReadFile
提供并打印所有输出。如何使
ReadFile
在可用时立即读取该输出?MSDN表示,在
ENABLE_LINE_INPUT
模式下,ReadFile
不会返回,直到达到CR
或缓冲区已满。该程序使用Linux换行符LF
,而不是Windows的CRLF
。我使用了小缓冲区32字节,并禁用了ENABLE_LINE_INPUT
(顺便问一下,禁用它的正确方法是什么?)。也许
ReadFile
之所以不返回,是因为Cygwin程序本身存在其他问题,而不仅仅是LF
换行符?但是在Windows的cmd.exe
中运行良好,为什么在Delphi控制台应用程序中不行?const
CommandExe:string = 'iperf3.exe ';
CommandLine:string = '-c 192.168.1.11 -u -b 1m -t 8 -p 5001 -l 8k -f m -i 2';
WorkDir:string = 'D:\PAS\iperf3\win32';// no trailing \
var
SA: TSecurityAttributes;
SI: TStartupInfo;
PI: TProcessInformation;
StdOutPipeRead, StdOutPipeWrite: THandle;
WasOK,CreateOk: Boolean;
Buffer: array[0..255] of AnsiChar;// 31 is Ok
BytesRead: Cardinal;
Line:ansistring;
try// except
with SA do begin
nLength := SizeOf(SA);
bInheritHandle := True;
lpSecurityDescriptor := nil;
end;
CreatePipe(StdOutPipeRead, StdOutPipeWrite, @SA, 0);
try
with SI do
begin
FillChar(SI, SizeOf(SI), 0);
cb := SizeOf(SI);
dwFlags := STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES;
wShowWindow := SW_HIDE;
hStdInput := GetStdHandle(STD_INPUT_HANDLE); // don't redirect stdin
hStdOutput := StdOutPipeWrite;
hStdError := StdOutPipeWrite;
end;
Writeln(WorkDir+'\'+CommandExe+' ' + CommandLine);
CreateOk := CreateProcess(nil, PChar(WideString(WorkDir+'\'+CommandExe+' ' + CommandLine)),
@SA, @SA, True,// nil, nil,
CREATE_SUSPENDED or CREATE_NEW_PROCESS_GROUP or NORMAL_PRIORITY_CLASS or CREATE_DEFAULT_ERROR_MODE,// 0,
nil,
PChar(WideString(WorkDir)), SI, PI);
CloseHandle(StdOutPipeWrite);// must be closed here otherwise ReadLn further doesn't work
ResumeThread(PI.hThread);
if CreateOk then
try// finally
repeat
WasOK := ReadFile(StdOutPipeRead, Buffer, SizeOf(Buffer), BytesRead, nil);
if BytesRead > 0 then
begin
Buffer[BytesRead] := #0;
Line := Line + Buffer;
Writeln(Line);
end;
until not WasOK or (BytesRead = 0);
ReadLn;
WaitForSingleObject(PI.hProcess, INFINITE);
finally
CloseHandle(PI.hThread);
CloseHandle(PI.hProcess);
end;
finally
CloseHandle(StdOutPipeRead);
end;
except
on E: Exception do
Writeln('Exception '+E.ClassName, ': ', E.Message);
end;
此外:为什么我们必须在 CreateProcess 后立即关闭此句柄?它用于读取程序输出:
CloseHandle(StdOutPipeWrite);
如果我在程序结束时关闭它,程序的输出是正常的,但ReadLn永远不会被读取以停止程序。
如何测试所有这些: 在一个命令窗口中启动iperf3服务器并让它监听:
D:\PAS\iperf3\win32>iperf3.exe -s -i 2 -p 5001
-----------------------------------------------------------
Server listening on 5001
-----------------------------------------------------------
在另一个命令窗口中,您启动客户端,它会立即连接到服务器并开始每2秒打印输出:
D:\PAS\iperf3\win32>iperf3.exe -c 192.168.1.11 -u -b 1m -t 8 -p 5001 -l 8k -f m -i 2
Connecting to host 192.168.1.11, port 5001
[ 4] local 192.168.1.11 port 52000 connected to 192.168.1.11 port 5001
[ ID] Interval Transfer Bandwidth Total Datagrams
[ 4] 0.00-2.00 sec 240 KBytes 0.98 Mbits/sec 30
[ 4] 2.00-4.00 sec 240 KBytes 0.98 Mbits/sec 30
[ 4] 4.00-6.00 sec 248 KBytes 1.02 Mbits/sec 31
[ 4] 6.00-8.00 sec 240 KBytes 0.98 Mbits/sec 30
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval Transfer Bandwidth Jitter Lost/Total Datagrams
[ 4] 0.00-8.00 sec 968 KBytes 0.99 Mbits/sec 0.074 ms 0/121 (0%)
[ 4] Sent 121 datagrams
iperf Done.
服务器也会打印输出,与客户端一起:
Accepted connection from 192.168.1.11, port 36719
[ 5] local 192.168.1.11 port 5001 connected to 192.168.1.11 port 52000
[ ID] Interval Transfer Bandwidth Jitter Lost/Total Datagrams
[ 5] 0.00-2.00 sec 240 KBytes 983 Kbits/sec 0.052 ms 0/30 (0%)
[ 5] 2.00-4.00 sec 240 KBytes 983 Kbits/sec 0.072 ms 0/30 (0%)
[ 5] 4.00-6.00 sec 248 KBytes 1.02 Mbits/sec 0.077 ms 0/31 (0%)
[ 5] 6.00-8.00 sec 240 KBytes 983 Kbits/sec 0.074 ms 0/30 (0%)
[ 5] 8.00-8.00 sec 0.00 Bytes 0.00 bits/sec 0.074 ms 0/0 (nan%)
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval Transfer Bandwidth Jitter Lost/Total Datagrams
[ 5] 0.00-8.00 sec 0.00 Bytes 0.00 bits/sec 0.074 ms 0/121 (0%)
-----------------------------------------------------------
Server listening on 5001
-----------------------------------------------------------
iperf3客户端在命令窗口中运行良好。现在让我们在客户端模式下启动“我的”代码,而iperf3服务器仍在侦听。服务器接受连接并开始打印输出。
Accepted connection from 192.168.1.11, port 36879
[ 5] local 192.168.1.11 port 5001 connected to 192.168.1.11 port 53069
[ ID] Interval Transfer Bandwidth Jitter Lost/Total Datagrams
[ 5] 0.00-2.00 sec 240 KBytes 983 Kbits/sec 0.033 ms 0/30 (0%)
[ 5] 2.00-4.00 sec 240 KBytes 983 Kbits/sec 0.125 ms 0/30 (0%)
[ 5] 4.00-6.00 sec 248 KBytes 1.02 Mbits/sec 0.106 ms 0/31 (0%)
[ 5] 6.00-8.00 sec 240 KBytes 983 Kbits/sec 0.109 ms 0/30 (0%)
[ 5] 8.00-8.00 sec 0.00 Bytes 0.00 bits/sec 0.109 ms 0/0 (nan%)
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval Transfer Bandwidth Jitter Lost/Total Datagrams
[ 5] 0.00-8.00 sec 0.00 Bytes 0.00 bits/sec 0.109 ms 0/121 (0%)
-----------------------------------------------------------
Server listening on 5001
-----------------------------------------------------------
这意味着iperf3客户端在“我的”代码中启动,但它没有打印任何内容!只有在客户端完成后,“我的”代码才会打印此输出。
Connecting to host 192.168.1.11, port 5001
[ 4] local 192.168.1.11 port 53069 connected to 192.168.1.11 port 5001
[ ID] Interval Transfer Bandwidth Total Datagrams
[ 4] 0.00-2.00 sec 240 KBytes 0.98 Mbits/sec 30
[ 4] 2.00-4.00 sec 240 KBytes 0.98 Mbits/sec 30
[ 4] 4.00-6.00 sec 248 KBytes 1.02 Mbits/sec 31
[ 4] 6.00-8.00 sec 240 KBytes 0.98 Mbits/sec 30
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval Transfer Bandwidth Jitter Lost/Total Datagrams
[ 4] 0.00-8.00 sec 968 KBytes 0.99 Mbits/sec 0.109 ms 0/121 (0%)
[ 4] Sent 121 datagrams
iperf Done.
因此,Cygwin程序输出的行为取决于它是在命令窗口还是Delphi控制台应用程序中运行。我的“Line”输出处理代码并不完美,但让我们找出如何使ReadFile实时返回,我会修复其余部分。