Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/275.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# NetworkStream异步读取->;取消_C#_.net_Sockets - Fatal编程技术网

C# NetworkStream异步读取->;取消

C# NetworkStream异步读取->;取消,c#,.net,sockets,C#,.net,Sockets,目前,我尝试在网络流中异步读写。我的软件是客户端,服务器可以自己发送信息或响应我发送给他的命令 所以我需要一个插座 始终读取(如果服务器发送状态信息) 当我想要发送命令时停止读取(命令可以是具有多表写入和读取操作的数据序列) 因此,我认为创建一个信号量和一个后台任务来处理服务器发送的消息是一个很好的方法,如果我想发送一个命令,我会阻止信号量,并完全访问套接字的读/写操作 以下是我目前的工作 private TcpClient _tcpClient = new TcpClient(); pro

目前,我尝试在网络流中异步读写。我的软件是客户端,服务器可以自己发送信息或响应我发送给他的命令

所以我需要一个插座

  • 始终读取(如果服务器发送状态信息)
  • 当我想要发送命令时停止读取(命令可以是具有多表写入和读取操作的数据序列)
因此,我认为创建一个信号量和一个后台任务来处理服务器发送的消息是一个很好的方法,如果我想发送一个命令,我会阻止信号量,并完全访问套接字的读/写操作

以下是我目前的工作

private TcpClient _tcpClient = new TcpClient();
protected SemaphoreSlim ClientSemaphore { get; } = new SemaphoreSlim(1, 1);

public async Task ConnectAsync()
{
    if (_tcpClient.Connected)
    {
        await DisconnectAsync();
    }
    await _tcpClient.ConnectAsync(Hostname, RemotePort);

    //here the background Task is started
    _ = AutoReceiveMessages();
}

private async Task AutoReceiveMessages()
{
    while (_tcpClient.Connected)
    {
        //enter and lock semaphore
        await ClientSemaphore.WaitAsync();
        try
        {
            //read from socket until timeout (ms)
            var msg = await ReadFromSocket(2000);
            foreach (var cmd in SplitMessageInTelegrams(msg))
            {
                Console.WriteLine("MESSAGE --> " + cmd);                    
            }
        }
        catch (Exception ex)
        {
        }
        finally
        {
            //release semaphore
            ClientSemaphore.Release();
        }
    }
}

private async Task<string> ReadFromSocket(double timeout = 0)
{
    var buf = new byte[4096];
    var stream = _tcpClient.GetStream();

    //read from stream or timeout
    var amountReadTask = stream.ReadAsync(buf, 0, buf.Length);
    var timeoutTask = Task.Delay(TimeSpan.FromMilliseconds(timeout));

    await Task.WhenAny(timeoutTask, amountReadTask)
              .ConfigureAwait(false);

    //timeout
    if (!amountReadTask.IsCompleted)
    {
        throw new TimeoutException("Timeout");
    }

    //no timeout
    return Encoding.ASCII.GetString(buf, 0, amountReadTask.Result);
}
我知道在这种情况下,我不需要信号量,但稍后我想创建序列,以便一个命令包含多表写入和读取,只要执行该命令,我就不想使用AutoReceiveMessages方法

现在的问题是

  • 如果我这样使用它,我永远不会得到响应ReadFromSocket方法总是得到超时,即使wireshark告诉我服务器已经响应
  • 但如果我禁用AutoReceiveMessages(只需注释=AutoReceiveMessages())并在SendTelegramAsync()中直接使用ReadFromSocket,则效果会更好,一切正常
因此,我认为问题与后台任务和ReadAsync有关,但我无法解决…

明白了

stream.DataAvailable是您的朋友(或我的朋友:))

如果我在ReadAsync之前检查数据是否可用,那么我就没有问题了

if (_tcpClient.GetStream().DataAvailable)
    var msg = await ReadFromSocket(DEFAULT_TIMEOUT);
if (_tcpClient.GetStream().DataAvailable)
    var msg = await ReadFromSocket(DEFAULT_TIMEOUT);