I have decided to implement a simple client-server-client implementation utilizing multithreading. The problem I encountered is that the every second message sent from client A to client B goes back to the client A. I am not entirely sure why is that happening. My educated guess is the combination of multithreading and sender IPEndPoint passed as reference, however I don't really see any way to workaround the reference. Here are snippets of the code:
Server code:
using System;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace UDP
{
public sealed class UdpServer
{
public static void Main()
{
var ipEndPoint = new IPEndPoint(IPAddress.Loopback, 12345);
var udpServer = new UdpClient(ipEndPoint);
var clientOne = new IPEndPoint(IPAddress.Loopback, 12346);
var clientTwo = new IPEndPoint(IPAddress.Loopback, 12347);
var taskFactory = new TaskFactory();
var tokenSource = new CancellationTokenSource();
var cancellationToken = tokenSource.Token;
var taskArray = new Task[2];
taskArray[0] = taskFactory.StartNew(() => MessagingTask(udpServer, clientOne, clientTwo, tokenSource, cancellationToken), cancellationToken);
taskArray[1] = taskFactory.StartNew(() => MessagingTask(udpServer, clientTwo, clientOne, tokenSource, cancellationToken), cancellationToken);
Task.WaitAny(taskArray);
}
private static void MessagingTask(UdpClient udpServer, IPEndPoint sender, IPEndPoint receiver, CancellationTokenSource tokenSource, CancellationToken cancellationToken)
{
while (!cancellationToken.IsCancellationRequested)
{
var bytes = udpServer.Receive(ref sender);
var message = Encoding.ASCII.GetString(bytes, 0, bytes.Length);
Console.WriteLine($"IP: {sender.Address} Port: {sender.Port}, {DateTime.Now}: {message}");
udpServer.Send(bytes, bytes.Length, receiver);
Console.WriteLine($"Send to: {receiver.Address} Port: {receiver.Port}, {DateTime.Now}: {message}");
}
}
}
}
Client code:
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace UDP
{
public sealed class UdpClientOne
{
public static void Main()
{
var clientEndpoint = new IPEndPoint(IPAddress.Loopback, 12346);
var serverEndpoint = new IPEndPoint(IPAddress.Loopback, 12345);
var udpClient = new UdpClient(clientEndpoint);
var taskFactory = new TaskFactory();
var tokenSource = new CancellationTokenSource();
var cancellationToken = tokenSource.Token;
var taskArray = new Task[2];
taskArray[0] = taskFactory.StartNew(() => ReadingThread(udpClient, serverEndpoint, cancellationToken), cancellationToken);
taskArray[1] = taskFactory.StartNew(() => SendingThread(udpClient, serverEndpoint, tokenSource, cancellationToken), cancellationToken);
Task.WaitAny(taskArray);
udpClient.Close();
}
private static void ReadingThread(UdpClient udpClient, IPEndPoint ipEndPoint, CancellationToken cancellationToken)
{
while (true)
{
if (cancellationToken.IsCancellationRequested)
{
Console.WriteLine("Closing application...");
return;
}
var data = udpClient.Receive(ref ipEndPoint);
var message= Encoding.ASCII.GetString(data, 0, data.Length);
Console.WriteLine($"{DateTime.Now}: {message}");
}
}
private static void SendingThread(UdpClient udpClient, IPEndPoint ipEndPoint, CancellationTokenSource tokenSource, CancellationToken cancellationToken)
{
string userInput = "";
while (true)
{
userInput = Console.ReadLine();
if (string.IsNullOrEmpty(userInput))
continue;
if (userInput.Equals("q"))
{
Console.WriteLine("Closing application...");
tokenSource.Cancel();
}
var bytes = Encoding.ASCII.GetBytes(userInput);
udpClient.Send(bytes, bytes.Length, ipEndPoint);
}
}
}
}
Console output:

