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

时间:2018-03-16 07:52:10

标签: 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 port)
repeat endlessly

问题是,如果没有要读取的数据,则从命名管道读取将被阻止,直到数据到来。因此,另一方通信(com端口到管道)也被阻止。

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

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

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

  • 或读操作超时,因此在超时后可能会发生写操作(在此应用程序中时间不是那么重要)。

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

命名管道是客户端(由其他软件创建的服务器),但如果更方便,也可以是服务器。

任何想法?!? 提前谢谢!

2 个答案:

答案 0 :(得分:0)

  

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

如果使用正确的选项,管道可以同时用于读取和写入。这是一个玩具示例,演示了客户和服务器不同意他们将执行操作的顺序,并且它只是在工作:

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方法来启动读写线程"而不是手动管理线程或任务)

答案 1 :(得分:0)

感谢Damien,你的答案对我没什么帮助,但我自己想出来了: 我已经尝试过使用readAsync,但它工作得不好,因为我的管道没有打开为Asynchronous:

pipe = new NamedPipeClientStream(".", "thePipe", PipeDirection.InOut, PipeOptions.Asynchronous);

然后,不加阻塞地读取管道:

pipe.ReadAsync (buffer, 0, buffer.Lenght).ContinueWith (t=> 
{
    //called when read is finished (data available).
});

最后,由于在while(1)循环中调用了read,我需要防止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)。

希望它会帮助别人。