I’m working on an application that requires a very responsive TCP communication across two PC (connected through direct Ethernet). I’ve used the code below to benchmark the responsiveness of the TCP socket (both TCP Server & TCP Client):
TCP Server
class Program
{
static void Main(string[] args)
{
string serverAddress = "192.168.23.88"; // Localhost
int serverPort = 6012;
TcpListener server = new TcpListener(IPAddress.Parse(serverAddress), serverPort);
server.Server.NoDelay = true;
server.Start();
Console.WriteLine($"Server started {serverAddress}:{serverPort}...");
while (true)
{
var client = server.AcceptTcpClient();
client.NoDelay = true;
Console.WriteLine("Client connected...");
HandleClientAsync(client); // Fire and forget
}
}
private static void HandleClientAsync(TcpClient client)
{
using (client)
{
var buffer = new byte[20];
var stream = client.GetStream();
var t1RP = Encoding.UTF8.GetBytes("<TEST,1>");
var t2RP = Encoding.UTF8.GetBytes("<TEST,2>");
var t3RP = Encoding.UTF8.GetBytes("<TEST,3>");
List<string> consoleList = new List<string>();
//string tmp = "";
while (true)
{
int bytesRead;
try
{
bytesRead = stream.Read(buffer, 0, buffer.Length);
}
catch (Exception e)
{
Console.WriteLine($"Error reading from client: {e.Message}");
foreach (var a in consoleList)
Console.WriteLine(a);
break;
}
stream.Write(sovRP, 0, t1RP.Length);
stream.Write(grbRP, 0, t2RP.Length);
stream.Write(resRP, 0, t3RP.Length);
}
}
}
}
TCP Client
static async Task Main(string[] args)
{
string serverAddress = "192.168.23.88"; // Localhost
int serverPort = 6012;
using (TcpClient client = new TcpClient())
{
try
{
int cycle = 5000;
client.NoDelay = true;
Console.WriteLine("Connecting to server...");
await client.ConnectAsync(serverAddress, serverPort);
Console.WriteLine($"{DateTime.Now:HH:mm:ss.fff} Connected to server {serverAddress}:{serverPort}");
Stopwatch time = new Stopwatch();
Stopwatch elapsedTime = new Stopwatch();
var stream = client.GetStream();
int count = 0;
{
byte[] buffer = new byte[20];
for (int i = 0; i < cycle; ++i)
{
long responseTime = 0;
long grabTime = 0;
long resultTime = 0;
byte[] data = Encoding.UTF8.GetBytes($"<SOV,1,4,>");
stream.Write(data, 0, data.Length);
_ = stream.FlushAsync();
elapsedTime.Restart();
string combined = "";
while (true)
{
int bytesRead = stream.Read(buffer, 0, buffer.Length);
combined += Encoding.UTF8.GetString(buffer, 0, bytesRead);
if (combined.Contains("<TEST,1>"))
{
_ = stream.FlushAsync();
responseTime = elapsedTime.ElapsedMilliseconds;
combined = combined.Replace("<TEST,1>", "");
if (responseTime > 3)
{
Console.WriteLine($"{DateTime.Now:HH:mm:ss.fff} SOV Response Time {responseTime}");
responseTime = elapsedTime.ElapsedMilliseconds;
count++;
}
break;
}
}
//Console.WriteLine($"{DateTime.Now:HH:mm:ss.fff} Received from server: {response}");
while (true)
{
int bytesRead = stream.Read(buffer, 0, buffer.Length);
combined += Encoding.UTF8.GetString(buffer, 0, bytesRead);
if (combined.Contains("<TEST,2>"))
{
grabTime = elapsedTime.ElapsedMilliseconds - responseTime;
combined = combined.Replace("<TEST,2>", "");
if (grabTime > 3)
{
_ = stream.FlushAsync();
Console.WriteLine($"{DateTime.Now:HH:mm:ss.fff} SOV Grab Time {grabTime}");
grabTime = elapsedTime.ElapsedMilliseconds - responseTime;
count++;
}
break;
}
}
//Console.WriteLine($"{DateTime.Now:HH:mm:ss.fff} Received from server: {response}");
while (true)
{
int bytesRead = stream.Read(buffer, 0, buffer.Length);
combined += Encoding.UTF8.GetString(buffer, 0, bytesRead);
if (combined.Contains("<TEST,3>"))
{
resultTime = elapsedTime.ElapsedMilliseconds - responseTime - grabTime;
combined = combined.Replace("<TEST,3>", "");
if (resultTime > 10)
{
_ = stream.FlushAsync();
Console.WriteLine($"{DateTime.Now:HH:mm:ss.fff} SOV Result Time {resultTime}");
resultTime = elapsedTime.ElapsedMilliseconds - responseTime - grabTime;
count++;
}
break;
}
}
//Console.WriteLine($"{DateTime.Now:HH:mm:ss.fff} Received from server: {response}");
time.Restart();
while (time.ElapsedMilliseconds < 50)
{
}
if ((i % 50) == 0)
Console.WriteLine($"Complete {i} Cycle");
}
}
Console.WriteLine($"{DateTime.Now:HH:mm:ss.fff} Completed {cycle} Cycle, Exceed Count {count}");
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
Console.ReadLine();
}
Console.WriteLine("Connection closed");
}
I’ve noticed that in 5000 cycles, I will randomly get some delayed response (5ms – 20ms).
I’ve used WireShark to monitor the TCP stream in both Server and Client. In Server side, TCP is sent out immediately but in Client side, there’s some latency:
Server Side
Client Side
Is there anything I have missing out in TCP configuration?
Thanks in advance.