我决定利用多线程实现一个简单的客户机-服务器-客户机实现.我遇到的问题是,从客户端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);
        }
    }
}

}

控制台输出:

Console output

推荐答案

UdpServer的服务器(端口号:12345)正在从客户端A(端口号:12346)接收消息,然后转发到客户端B(端口号:12347).然而,UdpClientOne的服务器105向客户端A发送数据,106也从客户端A发送数据.

enter image description here

图中蓝色代表UdpServer级,红色代表UdpClientOne级.两个箭头指向服务器(12345端口),因此它将接收两次消息.

Csharp相关问答推荐

Rx.Net -当关闭序列被触发时如何聚合消息并发出中间输出?

有没有方法让ASP.NET Core模型绑定器使用私有设置器来设置属性?

Dapper是否可以自动扩展类成员

当我使用NET6作为目标框架时,为什么DotNet使用NET8作为MS包?

如何修改中间件或其注册以正确使用作用域服务?

在发布表单时绑定包含附加(嵌套)列表的对象列表的正确语法是什么

在实时数据库中匹配两个玩家的问题

从Blob存储中提取tar.gz文件并将提取结果上载到另一个Blob存储

如何在Parall.ForEachAsync中使用CancerationTokenSource

Blazor WebApp:原始异常:AADSTS700025:客户端是公共的,因此既不应显示客户端,也不应显示客户端

如何将ASP.NET Core 2.1(在.NET框架上运行)更新到较新的版本?

从依赖项容器在.NET 8中的Program.cs文件中添加IOC

如何使用C#中的主构造函数功能使用多个构造函数?

在两个已具有一对多关系的表之间添加另一个一对多关系

对于PowerShell中的ConvertTo-SecureString方法,Microsoft如何将初始化向量添加到AES加密中的安全字符串?

如何避免在.NET中将日志(log)写入相对路径

Blazor Server/.NET 8/在初始加载时调用异步代码是否冻结屏幕,直到第一次异步调用完成?

如何从Azure函数使用Graph API(SDK 5.35)中的[FindMeetingTimes]

如何在C#控制台应用程序中获取用户输入并将其作为订单项目进行处理?

如何对构建在Clean架构和CQRS之上的控制器进行单元测试?