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