[英]NetworkStream Async Read -> Cancel
目前我嘗試從網絡流讀取和寫入異步。 我的軟件是客戶端部分,服務器可以自行發送信息或響應我發送給他的命令。
所以我需要一個插座
所以我認為創建一個信號量和一個后台任務來處理服務器發送的消息是一個很好的方法,如果我想發送一個命令,我會阻止信號量並擁有對套接字的讀/寫操作的完全訪問權限。
這是我目前所做的。
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);
}
但這不像我預期的那樣工作......我使用這種方法向服務器發送消息,在 WireShark 中我看到服務器響應相同的消息
protected async Task SendTelegramAsync(ITelegram telegram)
{
await ClientSemaphore.WaitAsync();
try
{
_ = telegram ?? throw new ArgumentException($"{nameof(telegram)}");
if (!_tcpClient.Connected) throw new InvalidOperationException("Socket not connected!");
var buf = new byte[4096];
var stream = _tcpClient.GetStream();
var msg = Encoding.ASCII.GetBytes("\x02" + telegram.GetCommandMessage() + "\x03");
Console.WriteLine("WRITE --> " + msg);
await stream.WriteAsync(msg, 0, msg.Length);
//comment AutoReceiveMessage and remove comment from this
//and I get responses from the server
//var test = await ReadFromSocket(2000);
}
finally
{
ClientSemaphore.Release();
}
}
我知道在這種情況下我不需要信號量,但后來我想創建序列,因此一個命令由多次寫入和讀取組成,只要執行該命令,我就不想使用 AutoReceiveMessages 方法。
現在的問題是
所以我認為問題與后台任務和 ReadAsync 有關,但我無法弄清楚......
知道了!
stream.DataAvailable 是您的朋友(或我的朋友 :))。
如果我在 ReadAsync 之前檢查是否 DataIsAvailable 那么我就沒有問題了。
if (_tcpClient.GetStream().DataAvailable)
var msg = await ReadFromSocket(DEFAULT_TIMEOUT);
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.