2 votes

Chaque seconde message est envoyé à l'expéditeur au lieu du destinataire dans l'implémentation client-serveur-client UDP

J'ai décidé de mettre en œuvre une implémentation client-serveur-client simple utilisant le multithreading. Le problème que j'ai rencontré est que chaque deuxième message envoyé du client A au client B revient au client A. Je ne suis pas tout à fait sûr de pourquoi cela se produit. Ma supposition éclairée est la combinaison du multithreading et de l'IPEndPoint de l'expéditeur passé par référence, cependant je ne vois vraiment aucun moyen de contourner cette référence. Voici des extraits de code :

Code serveur :

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

Code client :

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("Fermeture de l'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("Fermeture de l'application...");
                tokenSource.Cancel();
            }

            var bytes = Encoding.ASCII.GetBytes(userInput);
            udpClient.Send(bytes, bytes.Length, ipEndPoint);
        }
    }
}

}

Sortie dans la console :

Sortie dans la console

1voto

Péter Szilvási Points 76

Le serveur de UdpServer (numéro de port : 12345) reçoit le message du client A (numéro de port : 12346) puis le transfère au client B (numéro de port : 12347). Cependant, le serveur de UdpClientOne envoie des données au Client A et reçoit également des données du Client A.

description de l'image ici

Sur l'image, la couleur bleue représente la classe UdpServer et la couleur rouge représente la classe UdpClientOne. Deux flèches pointent vers le serveur (port 12345), il recevra donc le message deux fois.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X