我遇到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:
这是服务器的典型输出,在这种情况下连续三次运行客户端:
Press X to exit Message received, 110 bytes: !"#$%&'()*+,-./0!"#$%&'()*+,-./0123456789:;?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ Message received, 94 bytes: !"#$%&'()*+,-./0123456789:;?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ Message received, 94 bytes: !"#$%&'()*+,-./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程序的插件:(
答案 0 :(得分:0)
我尝试改变的第一件事就是:
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
条件。
答案 1 :(得分:0)
我明白了。
(这在NamedPipeServerStream中不是问题。)
看起来这是由于DOS系统调用选择不当造成的。如果我通过INT 0x21 / AH = 0x3D使用打开调用,它可以正常工作。 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: