У меня проблема с 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, на самом деле ведет себя правильно.
Запуск Process Monitor, когда тестовые клиенты работаютЗапуск показывает, что DOS-1 иногда имеет результат ОТМЕНА для WriteFile, а клиент Windows - нет.Небольшая проблема, так как предполагается, что это дополнение для DOS-программы: (