I’m having difficulty receiving messages on the network when they are sent in quick succession. I can see the messages in wireshark so they are getting out, but my code is hanging reading the message. Below is a simple version of my code that demonstrates the problem:
Agent.cs
using System.Collections.Concurrent;
using System.Net.Sockets;
namespace Network;
public class Agent
{
private readonly TcpClient client;
private bool running;
private readonly ConcurrentQueue<byte[]> receiveQueue = new();
public Agent(TcpClient client)
{
this.client = client;
running = true;
Task.Run(ReceiveMessagesAsync);
}
public void Stop()
{
running = false;
client.Close();
}
private async Task ReceiveMessagesAsync()
{
var buffer = new byte[1024];
while (running)
{
var networkStream = client.GetStream();
if (networkStream.DataAvailable)
{
int bytesRead = await networkStream.ReadAsync(buffer, 0, buffer.Length);
if (bytesRead > 0)
{
var message = new byte[bytesRead];
Array.Copy(buffer, message, bytesRead);
receiveQueue.Enqueue(message);
}
}
else
{
await Task.Delay(100);
}
}
}
public bool TryReadMessage(out byte[] message)
{
receiveQueue.TryDequeue(out byte[]? buffer);
if (buffer != null)
{
message = buffer;
return true;
}
message = [];
return false;
}
public async Task SendMessageAsync(byte[] message)
{
if (client?.Connected ?? false)
{
await client.GetStream().WriteAsync(message);
}
// Console.WriteLine("Message sent");
}
}
Listener.cs
using System.Net;
using System.Net.Sockets;
namespace Network;
public class Listener
{
private readonly TcpListener listener;
private bool running;
public delegate Task ClientConnectedCallback(Agent client);
private readonly ClientConnectedCallback clientConnected;
public Listener(int port, ClientConnectedCallback callback)
{
listener = new TcpListener(IPAddress.Any, port);
clientConnected += callback;
}
public void Start()
{
running = true;
listener.Start();
Task.Run(AcceptClientsAsync);
}
public void Stop()
{
running = false;
listener.Stop();
}
private async Task AcceptClientsAsync()
{
while (running)
{
var client = await listener.AcceptTcpClientAsync();
_ = clientConnected(new Agent(client));
}
}
}
Server Program.cs
using Network;
namespace Server;
class Program
{
private static async Task ClientConnectedCallback(Agent client)
{
Console.WriteLine("Client Connected");
try
{
while (true)
{
if (client.TryReadMessage(out var message))
{
if (message[0] == 0x00)
{
Console.WriteLine($"Received message: {message[0]} {message[1]}");
// Ack
Console.WriteLine("Sending Ack");
var response = new byte[] { 0x01, message[1] };
await client.SendMessageAsync(response);
await Task.Delay(500);
// Reply
Console.WriteLine("Sending Reply");
var reply = new byte[] { 0x00, message[1] };
await client.SendMessageAsync(reply);
}
else if (message[0] == 0x01)
{
// Ack
Console.WriteLine($"Got Ack: {message[1]}");
}
}
else
{
await Task.Delay(100);
}
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
Console.WriteLine("Done");
}
static async Task Main(string[] args)
{
var server = new Listener(13400, ClientConnectedCallback);
server.Start();
Console.WriteLine("Server started. Listening on port 13400...");
while (true)
{
await Task.Delay(1000);
}
}
}
Client program.cs
using System.Net.Sockets;
using Network;
namespace Client;
public class TcpClientProgram
{
public static async Task Main(string[] args)
{
var server = "127.0.0.1";
var port = 13400;
var client = new TcpClient(server, port);
var clientProgram = new Agent(client);
int nextMessageId = 0;
while (true)
{
byte[] message = [0x00, (byte)nextMessageId];
await clientProgram.SendMessageAsync(message);
Console.WriteLine($"Sent Message: {message[0]} {message[1]}");
while (true)
{
if (clientProgram.TryReadMessage(out var response))
{
if (response[0] == 0x00)
{
Console.WriteLine($"Received Reply: {response[1]}");
// Ack
Console.WriteLine("Sending Ack");
byte[] ack = [0x01, response[1]];
await clientProgram.SendMessageAsync(ack);
nextMessageId++;
break;
}
else if (response[0] == 0x01)
{
Console.WriteLine($"Got Ack: {response[1]}");
}
}
else
{
await Task.Delay(100);
}
}
}
}
}
From the client application I get this output:
Sent Message: 0 0
Got Ack: 0
Received Reply: 0
Sending Ack
Sent Message: 0 1
and from the server application I get this output:
Server started. Listening on port 13400...
Client Connected
Received message: 0 0
Sending Ack
Sending Reply
Got Ack: 0
I would expect the server to receive the [0x00 0x01] message, but it is going missing. I’m on Mac if that helps any. Otherwise I’m a bit bamboozled.
Thanks for the help 🙂