TcpClient/NetworkStream 在同一实例上同时读写

TcpClient/NetworkStream read write simoultanously on same instance

我需要与一个只接受 1 个 TCP 连接的硬件进行通信。但是我找不到任何好的例子,其中相同的 NetworkStream 用于同时读取和写入。

MSDN documentation 表示如下:

Read and write operations can be performed simultaneously on an instance of the NetworkStream class without the need for synchronization. As long as there is one unique thread for the write operations and one unique thread for the read operations, there will be no cross-interference between read and write threads and no synchronization is required.

但是,我找不到一个示例来说明如何在不同的线程中使用 NetworkStream 的相同实例进行读写。

我不确定我是否应该:

在 TCP connections/network 通信方面,我远不是专家,所以肯定有一些我不完全理解的事情...

提前致谢:)

记住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, 0, 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, 0, 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, 0, 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, 0, sBuf.Length);
}).Start();

Console.ReadKey(true);

在上面的示例中,您有两个不同的线程,它们同时对底层流执行某些操作,并且没有任何“崩溃”。

至于你应该使用什么模式......你有几种可能性。您在上面的第一个示例中使用了任务(现代方法),或者您可以使用阻塞调用(“old-school”方法)执行线程化 while(true) 方法。或者 Begin...End... 方法(介于 old-school 和现代之间)。

什么最好?你选。我个人喜欢在数据可用时触发事件,所以我倾向于使用 BeginConnect/EndConnectBeginReceive/EndReceive 等方法。

尽管有时,我喜欢使用 ReadAsync() 执行 while(true),但使用 CancellationToken 来终止循环。

建议使用while(true)来阻止调用。有了 TPL 为我们提供的出色工具,我们不必再启动通用线程来完成任何事情。