问题描述
我需要与仅接受1个TCP连接的硬件进行通信。但是我找不到任何很好的例子,其中使用相同的NetworkStream
同时进行读写。
读写操作可以同时在 不需要的NetworkStream类的实例 同步。只要有一个唯一的写入线程 操作和一个用于读取操作的唯一线程, 在读写线程之间没有交叉干扰,并且没有 需要同步。
但是,我找不到一个示例来说明如何在不同的线程中使用NetworkStream
的相同实例进行读写。
我不确定是否应该:
- 仅将
NetworkStream
直接用于myNetworkStream.ReadAsync()
的阅读,或使用StreamReader
, - 仅将
NetworkStream
直接用于myNetworkStream.WriteAsync()
书写,或使用StreamWriter
, - 直接使用
while(true)
启动一个新线程,以在实例化TcpClient
时进行读取, - 保留对
NetworkStream
实例的全局引用,以便我可以在任何时候编写...
在TCP连接/网络通信方面,我还远非专家,所以肯定有些事情我还不完全了解...
预先感谢:)
解决方法
记住I / O绑定的任务there is no thread。
您发布的段落并没有真正处理任务,例如:
var client = new TcpClient();
await client.ConnectAsync("example.com",80);
var stream = client.GetStream();
// start reading from the socket
var rBuf = new byte[2048];
var tRecv = stream.ReadAsync(rBuf,rBuf.Length);
// send data and wait for it to complete
var sBuf = Encoding.UTF8.GetBytes("GET / HTTP/1.1\r\nHost: example.com\r\n\r\n");
await stream.WriteAsync(sBuf,sBuf.Length);
// now await for the data
var bytesRecv = await tRecv;
Console.WriteLine($"Received {bytesRecv} bytes");
在处理基础流时,没有两个同时执行的线程在同一时间做某事。
该段落所讨论的是在做这样的事情:
var client = new TcpClient();
await client.ConnectAsync("example.com",80);
var stream = client.GetStream();
new Thread(() =>
{
var rBuf = new byte[2048];
var bytesRecv = stream.Read(rBuf,rBuf.Length);
Console.WriteLine($"Received {bytesRecv} bytes");
}).Start();
Thread.Sleep(500); // ensure the above thread has started
new Thread(() =>
{
var sBuf = Encoding.UTF8.GetBytes("GET / HTTP/1.1\r\nHost: example.com\r\n\r\n");
stream.Write(sBuf,sBuf.Length);
}).Start();
Console.ReadKey(true);
在上面的示例中,您有两个不同的线程同时对基础流执行某项操作,并且没有“崩溃”。
就应该使用哪种模式...您有几种可能。您在上面的第一个示例中有任务(现代方法),或者可以使用阻塞调用(“老式”方法)来执行线程化while(true)
方法。或Begin...
和End...
方法(介于老式和现代之间)。
什么是最好的?你选。我个人喜欢在数据可用时触发事件,因此我倾向于使用BeginConnect
/ EndConnect
,BeginReceive
/ EndReceive
等方法。
尽管有时候,我喜欢使用while(true)
来进行ReadAsync()
,但是使用CancellationToken
来杀死循环。
我不建议您将while(true)
与阻塞呼叫一起使用。有了TPL为我们提供的出色工具,我们就不必再启动通用线程来完成任何事情。
我会使用流水线模式, 查看 This Gitub 代码和来自 David Fowler
的文章