C#命名管道获取要读取的字节数

C#命名管道获取要读取的字节数,c#,named-pipes,C#,Named Pipes,我正在用c语言编写一个简单的软件,它从一个命名管道(客户端)读取字节并将其转发到一个串行端口(对数据进行一些处理),反之亦然。它看起来像: if(data available on the named pipe) write on com port (the data read from the named pipe) if(data available on the com port) write on named pipe (the data read from the com

我正在用c语言编写一个简单的软件,它从一个命名管道(客户端)读取字节并将其转发到一个串行端口(对数据进行一些处理),反之亦然。它看起来像:

if(data available on the named pipe)
   write on com port (the data read from the named pipe) 
if(data available on the com port)
   write on named pipe (the data read from the com port)
repeat endlessly
问题是,如果没有数据可读取,则从命名管道读取的数据将被阻止,直到出现数据。因此,另一端的通信(com端口到管道)也被阻塞

我曾尝试在它自己的线程中运行双向通信,但在另一个线程上执行读取操作(或等待数据)时,管道上的写入操作被阻塞。 我尝试停止阻塞的线程并取消读取操作,但没有成功

处理这类事情的最简单方法是:

  • 获取管道上可读取的字节数,如果为0,则跳过读取

  • 或者在读操作上有一个超时,因此在超时之后可能会发生写操作(在这个应用程序中,计时不是那么关键)

这非常适合将com端口部分作为包含读取缓冲区中字节数的comPort.BytesToRead变量使用

命名管道是一个客户端(由另一个软件创建的服务器),但如果方便的话,也可以是一个服务器

有什么想法吗?!? 提前谢谢你

我曾尝试在它自己的线程中运行双向通信,但在另一个线程上执行读取操作(或等待数据)时,管道上的写入操作被阻塞

只要使用正确的选项,管道可以同时用于读写。下面是一个玩具示例,演示了客户机和服务器在执行操作的顺序上存在分歧,并且该操作正常工作:

using System;
using System.IO;
using System.Security.Cryptography;
using System.Threading.Tasks;
using System.IO.Pipes;
using System.Text;
using System.Threading;

public class Bob
{
  static void Main()
  {
    var svr = new NamedPipeServerStream("boris", PipeDirection.InOut, NamedPipeServerStream.MaxAllowedServerInstances, PipeTransmissionMode.Byte);
    var helper = Task.Run(() =>
    {
      var clt = new NamedPipeClientStream("localhost", "boris", PipeDirection.InOut, PipeOptions.Asynchronous);
      clt.Connect();
      var inBuff = new byte[256];
      var read = clt.ReadAsync(inBuff, 0, inBuff.Length);
      var msg = Encoding.UTF8.GetBytes("Hello!");
      var write = clt.WriteAsync(msg, 0, msg.Length);
      Task.WaitAll(read, write);
      var cltMsg = Encoding.UTF8.GetString(inBuff, 0, read.Result);
      Console.WriteLine("Client got message: {0}", cltMsg);
    });
    svr.WaitForConnection();
    var srvBuff = new byte[256];
    var srvL = svr.Read(srvBuff, 0, srvBuff.Length);
    var svrMsg = Encoding.UTF8.GetString(srvBuff, 0, srvL);
    Console.WriteLine("Server got message: {0}", svrMsg);
    var response = Encoding.UTF8.GetBytes("We're done now");
    svr.Write(response, 0, response.Length);
    helper.Wait();
    Console.WriteLine("It's all over");
    Console.ReadLine();
  }
}

(在现实世界中,我们会使用一些
async
方法来启动读写“线程”,而不是手动管理线程或任务)

谢谢Damien,你的回答对我帮助不大,但我自己想出来了: 我尝试过使用readAsync,但效果不佳,因为我的管道没有以异步方式打开:

pipe = new NamedPipeClientStream(".", "thePipe", PipeDirection.InOut, PipeOptions.Asynchronous);
然后,要在不堵塞的情况下读取管道:

pipe.ReadAsync (buffer, 0, buffer.Lenght).ContinueWith (t=> 
{
    //called when read is finished (data available).
});
最后,由于read是在while(1)循环中调用的,因此我需要防止read async被多次暂停:

if (readFinished) {     
    readFinished = false;
    pipe.ReadAsync (buffer, 0, buffer.Length).ContinueWith (t => {
        //called when read is finished (data available).
        //TODO: deal with the data (stored in 'buffer').
        readFinished = true;
    });
}
(使用“readFinished”将布尔值初始化为true)


希望它能帮助其他人。

这很正常。SerialPort具有DataReceived事件,可帮助您在不阻塞或轮询的情况下进行读取。或者可以使用它的BaseStream.ReadAsync()方法。管道也可以,beginhead()或更方便的名称dpipeclientstream.ReadAsync()。由于这解决了您的问题,请接受它作为您问题的答案。这将帮助未来的读者更快地找到答案。