在 UDP 客户端-服务器-客户端实现中,每第二条消息都会发送给发送者而不是接收者

Every second message gets send to sender instead of receiver in UDP client-server-client implementation

我决定使用多线程实现一个简单的客户端-服务器-客户端实现。我遇到的问题是,从客户端 A 发送到客户端 B 的每秒钟消息都会返回到客户端 A。我不完全确定为什么会这样。我有根据的猜测是多线程和作为参考传递的发送方 IPEndPoint 的组合,但是我真的看不到任何解决参考的方法。以下是代码片段:

服务器代码:

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}");
        }
    }
}
}

客户代码:

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);
        }
    }
}

}

控制台输出:

UdpServer的服务器(端口号:12345)正在接收来自客户端A(端口号:12346[=29)的消息=]),然后转发给客户端B(端口号:12347)。但是 UdpClientOne 的服务器 发送 数据给客户端 A 并且 接收 也来自客户端 A 的数据。

图中蓝色代表UdpServer class,红色代表UdpClientOne class。两个箭头指向服务器(12345端口),因此它会收到两次消息。