В настоящее время я пытаюсь читать и записывать Asyn c в / из сетевого потока. Мое программное обеспечение является клиентской частью, и сервер может отправлять информацию самостоятельно или отвечать на команды, которые я ему отправляю.
Поэтому мне нужен сокет, который
- читает все время (в если сервер отправляет информацию о состоянии)
- прекращает чтение, когда я хочу отправить команды (команды могут быть последовательностями данных с несколькими операциями записи и чтения)
Поэтому я подумал, что это будет хороший подход к созданию семафора и фоновой задачи, которая обрабатывает отправленные сервером сообщения, и в случае, если я хочу отправить команду, я блокирую семафор и получаю полный доступ к операциям чтения / записи в сокет.
Здесь это то, что я делаю в настоящее время.
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();
}
}
Я знаю, что в этом случае мне не нужен семафор, но позже я хочу создать последовательности, чтобы одна команда состояла из нескольких записей. es и читает, и пока команда выполняется, я не хочу использовать метод AutoReceiveMessages.
Теперь проблема заключается в
- Если я использую его таким образом, я никогда не получу В ответ метод ReadFromSocket всегда получает тайм-аут, даже когда Wireshark сообщает мне, что сервер ответил
- Но даже лучше, если я отключу AutoReceiveMessages (просто прокомментируем _ = AutoReceiveMessages ()) и использую ReadFromSocket непосредственно в SendTelegramAsyn c () все работает, как ожидалось.
Так что я думаю, что проблема связана с фоновой задачей и ReadAsyn c, но я не мог понять это ...