.NET NamedPipeServerStream 问题 - 连续读取返回相同的数据
Posted
技术标签:
【中文标题】.NET NamedPipeServerStream 问题 - 连续读取返回相同的数据【英文标题】:.NET NamedPipeServerStream problem - consecutive Reads return the same data 【发布时间】:2010-06-18 19:47:34 【问题描述】:我在使用 NamedPipeServerStream 时遇到问题 - 当我的代码读取数据时,它只是重复最后一个 Read
的输出,而没有获取新数据。
这是展示这种行为的最小服务器代码示例:
using System;
using System.IO;
using System.IO.Pipes;
using System.Text;
namespace ConsoleApplication1
class Program
static NamedPipeServerStream NPSS;
static void Main(string[] args)
string PipeName = "Test1";
// create asynchronous pipe server
NPSS = new NamedPipeServerStream(PipeName, PipeDirection.InOut, -1, PipeTransmissionMode.Message, PipeOptions.Asynchronous);
IAsyncResult resultConnect = NPSS.BeginWaitForConnection(NamedPipeConnectionCallback, null);
Console.WriteLine("Press X to exit\n\n");
while (Console.ReadKey(true).Key != ConsoleKey.X);
static void NamedPipeConnectionCallback(IAsyncResult resultConnection)
try
NPSS.EndWaitForConnection(resultConnection);
catch (OperationCanceledException) // this happens when calling thread (Main function) exits
return;
while (NPSS.CanRead)
// small buffer for demonstration purposes; it's much larger in the
// actual code, but still exhibits same problem
byte[] PipeDataBuffer = new byte[16];
MemoryStream MessageStream = new MemoryStream();
int TotalBytesRead = 0;
do
int BytesRead = NPSS.Read(PipeDataBuffer, 0, PipeDataBuffer.Length);
MessageStream.Write(PipeDataBuffer, 0, BytesRead);
TotalBytesRead += BytesRead;
while (!NPSS.IsMessageComplete);
byte[] Message = MessageStream.ToArray();
if (Message.Length == 0)
break;
Console.WriteLine(String.Format("Message received, 0 bytes:", TotalBytesRead));
Console.WriteLine(new ASCIIEncoding().GetString(Message));
NPSS.Disconnect();
NPSS.BeginWaitForConnection(NamedPipeConnectionCallback, null);
这是测试客户端(用 DOS 汇编程序编写,NASM 风格,编译为 .COM 文件)。它所做的只是将管道作为文件打开(\.\pipe\Test1)并向其中写入一些数据:
; NPTEST2.ASM
; - tests communication with named pipe
org 0x100
push cs
pop ds
mov si, pipename ; path
mov bx, 0x42 ; access/sharing mode
mov cx, 0 ; attributes
mov dx, 1 ; open file (not create/truncate)
mov ax, 0x716c ; long filename open
int 0x21
jc quit
push ax ; file handle returned in ax
pop bx ; file handle
push bx
mov ah, 0x40 ; write
mov cx, (testdata_end-testdata) ; size
mov dx, testdata ; ptr to data
int 0x21
pop bx ; file handle
mov ah, 0x3e ; close
int 0x21
quit:
mov ah,0x4c ; quit
int 0x21
pipename:
db "\\.\pipe\Test1",0
testdata:
db "!", 0x22, "#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz|~"
testdata_end:
这是服务器的典型输出,在这种情况下是连续运行客户端 3 次:
按 X 退出 收到的消息,110 字节: !"#$%&'()*+,-./0!"#$%&'()*+,-./0123456789:;?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz|~ 收到的消息,94 字节: !"#$%&'()*+,-./0123456789:;?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz|~ 收到的消息,94 字节: !"#$%&'()*+,-./0123456789:;?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz|~如您所见,第一条消息比应有的长度长 16 个字节(即一个缓冲区长度),因为前 16 个字节在开头重复。
到目前为止,我已经尝试过改变:
消息到字节的传输方式 在不同的主机上运行客户端和服务器,而不仅仅是在本地运行 使用异步BeginRead
和EndRead
调用而不是Read
仅使用WaitForConnection
和Read
将代码转换为完全同步的
但这些都没有对问题产生任何影响。
谁能说明我在这里做错了什么,或者我可以检查的其他事情?谢谢!
编辑: 进一步研究 - 使用 Windows 测试客户端而不是在 NTVDM(DOS 机器)下运行的测试客户端有所不同。也就是这段代码:
int main(int argc, char* argv[])
FILE *f = fopen("\\\\.\\pipe\\Test1", "r+b");
if (f)
fwrite("!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz|~", 94, 1, f);
fclose(f);
return 0;
应该相当于上面的 DOS 汇编代码,实际上行为正常。
在测试客户端运行时运行进程监视器显示 DOS 偶尔会出现针对 WriteFile 的 CANCELED 结果,而 Windows 客户端则没有。有点问题,因为这应该是 DOS 程序的插件 :(
【问题讨论】:
【参考方案1】:我要尝试更改的第一件事是:
do
// !!! problematic function call here !!!
int BytesRead = NPSS.Read(PipeDataBuffer, 0, PipeDataBuffer.Length);
// !!!
MessageStream.Write(PipeDataBuffer, 0, BytesRead);
TotalBytesRead += BytesRead;
while (!NPSS.IsMessageComplete);
它不检查BytesRead
是否为+ve;现在我会期望 MessageStream.Write
如果它是负面的,就会爆炸,但是......无论哪种方式;我肯定会在那里检查意外的<=0
条件。
【讨论】:
感谢您的建议 - 我添加了一些代码来打印 BytesRead 的值,并且每次都读取正确的数字,没有读取零字节或负字节。不幸的是,事实并非如此。【参考方案2】:我想通了。
(在 NamedPipeServerStream 中这不是问题。)
看起来这是由于 DOS 系统调用选择不当造成的。如果我通过 INT 0x21 / AH=0x3D 使用 open 调用,它可以正常工作。 Process Monitor 中的堆栈跟踪也显示了此方法的非常不同的代码路径。这一切都很奇怪,但至少它是有效的。我想这个技术信息对世界上没有其他人有用,但我想我还是会更新:)
; NPTEST3.ASM
; - tests communication with named pipe
org 0x100
push cs
pop ds
mov dx, pipename ; path
mov ax, 0x3d42 ; open
int 0x21
jc quit
push ax ; file handle returned in ax
pop bx ; file handle
push bx
mov ah, 0x40 ; write
mov cx, (testdata_end-testdata) ; size
mov dx, testdata ; ptr to data
int 0x21
pop bx ; file handle
mov ah, 0x3e ; close
int 0x21
quit:
mov ah,0x4c ; quit
int 0x21
pipename:
db "\\.\pipe\Test1",0
testdata:
db "!", 0x22, "#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz|~"
testdata_end:
【讨论】:
以上是关于.NET NamedPipeServerStream 问题 - 连续读取返回相同的数据的主要内容,如果未能解决你的问题,请参考以下文章
.NET平台系列26:在 Windows 上安装 .NET Core/.NET5/.NET6