简体   繁体   English

C#如何在重新连接NetworkStream时协调读写线程?

[英]C# How to coordinate read and write threads while reconnecting NetworkStream?

I have a thread writing requests to NetworkStream. 我有一个线程向NetworkStream写入请求。 Another thread is reading responses from this stream. 另一个线程正在读取此流的响应。

I want to make it fault tolerant. 我想让它容错。 In case of network failure, I want NetworkStream to be disposed replaced by a brand new one. 如果网络出现故障,我希望将NetworkStream替换为全新的。

I made the two threads handle IO/Socket exceptions. 我让两个线程处理IO / Socket异常。 Each of them will try to re-establish the connection. 他们每个人都会尝试重新建立连接。 I'm struggling to coordinate these two threads. 我正在努力协调这两个线程。 I had to place lock sections making the code rather complicated and error-prone. 我不得不放置锁定部分,使代码相当复杂且容易出错。

Is there a recommended way to implement this? 有没有推荐的方法来实现这个? Perhaps using a single thread but making Read or Write async? 也许使用单个线程但是进行读或写异步?

I find it easiest to have a single thread that handles coordination and writing and then handle reading using async. 我发现最简单的方法是让一个线程处理协调和写入,然后使用异步处理读取。 By including a CancellationTokenSource in an AsyncState object the reader code can signal the sending thread to restart the connection, when the receiver encounters an error (calling EndRead or if the stream completes). 通过在AsyncState对象中包含CancellationTokenSource ,当接收器遇到错误(调用EndRead或流完成时),读取器代码可以发信号通知发送线程重新启动连接。 The coordination/writer sits in a loop that creates the connection and then loops consuming a BlockingCollection<T> of items to send. 协调/写入器位于创建连接的循环中,然后循环使用要发送的项的BlockingCollection<T> By using BlockingCollection.GetConsumingEnumerable(token) the sender can be cancelled when the reader encounters an error. 通过使用BlockingCollection.GetConsumingEnumerable(token) ,可以在阅读器遇到错误时取消发件人。

    private class AsyncState
    {
        public byte[] Buffer { get; set; }
        public NetworkStream NetworkStream { get; set; }
        public CancellationTokenSource CancellationTokenSource { get; set; }
    }

Once you've created the connection you can start the async reading process (which keeps calling itself as long as everything is working). 一旦创建了连接,就可以启动异步读取过程(只要一切正常,它就会一直调用自己)。 Passing the buffer, the stream and the CancellationTokenSource in the state object: 在状态对象中传递缓冲区,流和CancellationTokenSource

var buffer = new byte[1];
stream.BeginRead(buffer, 0, 1, Callback,
   new AsyncState
   {
       Buffer = buffer,
       NetworkStream = stream,
       CancellationTokenSource = cts2
   });

After that you start reading from your output queue and writing to the stream until cancelled or a failure happens: 之后,您开始从输出队列中读取并写入流,直到取消或发生故障:

using (var writer = new StreamWriter(stream, Encoding.ASCII, 80, true))
{
    foreach (var item in this.sendQueue.GetConsumingEnumerable(cancellationToken))
    {
       ...

... and in the Callback you can check for failures and, if necessary, hit the CancellationTokenSource to signal the writer thread to restart the connection. ...在回调中,您可以检查失败,并在必要时点击CancellationTokenSource以通知写入程序线程重新启动连接。

private void Callback(IAsyncResult ar)
{
  var state = (AsyncState)ar.AsyncState;

  if (ar.IsCompleted)
  {
    try
    {
        int bytesRead = state.NetworkStream.EndRead(ar);
        LogState("Post read ", state.NetworkStream);
    }
    catch (Exception ex)
    {
        Log.Warn("Exception during EndRead", ex);
        state.CancellationTokenSource.Cancel();
        return;
    }

    // Deal with the character received
    char c = (char)state.Buffer[0];

    if (c < 0)
    {
        Log.Warn("c < 0, stream closing");
        state.CancellationTokenSource.Cancel();
        return;
    }

    ... deal with the character here, building up a buffer and
    ... handing it out to the application when completed
    ... perhaps using Rx Subject<T> to make it easy to subscribe

    ... and finally ask for the next byte with the same Callback

    // Launch the next reader
    var buffer2 = new byte[1];
    var state2 = state.WithNewBuffer(buffer2);
    state.NetworkStream.BeginRead(buffer2, 0, 1, Callback, state2);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM