web-dev-qa-db-fra.com

Envoi et réception de paquets UDP

Est-il possible de faire communiquer deux programmes distincts sur le même ordinateur (unidirectionnel) via UDP via localhost/127 ... en partageant le même numéro de port? 

Nous travaillons sur un projet étudiant dans lequel nous devons envoyer des paquets UDP contenant de la télémétrie entre deux ordinateurs. Le programme qui génère ces paquets est propriétaire, mais je travaille moi-même sur le programme récepteur en C # avec System.Net.Sockets.UdpClient et System.Net.IPEndPoint

Cela fonctionne bien lors des réunions de notre groupe lorsque nous avons plusieurs ordinateurs connectés sur lesquels nous pouvons exécuter les deux programmes séparément. Mais ce n'est pas très utile lorsque je suis chez moi et que j'essaye de développer le programme de traitement de télémétrie, car je n'ai qu'un ordinateur (j'ai besoin d'un flux pour tester le programme de traitement). Je ne peux pas installer le programme sur les ordinateurs de l'école non plus.

Lorsque j'essaie d'exécuter les deux programmes en même temps sur mon ordinateur (en commençant mon programme en dernier), je reçois une exception SocketException indiquant qu'une seule utilisation de chaque port est normalement autorisée. Ce qui me porte à penser qu’il doit exister un moyen de partager le port (bien qu’il soit logique que seul un programme puisse utiliser le port d’un ordinateur à la fois, je n’ai aucun mal à utiliser plusieurs navigateurs Internet à la fois (et supposons qu'ils utilisent le port 80 pour http)).

REEDIT de l'EDIT:

sipwiz avait raison, et grâce à Kalmi pour le pointeur sur UdpClient.Client.Bind () . À l’époque, cependant, nous envisageons d’utiliser un autre programme qui génère des paquets similaires et avec lequel nous pouvons partager le sur le même ordinateur en utilisant ma première approche (bien que naïve) avec la liaison du client UDP dans le cteur . Désolé de devoir désélectionner votre réponse, sysrqb.

35
Cecil Has a Name

Je ne m'attendais pas à ce que cela soit possible, mais… bien… sipwiz avait raison.

Cela peut être fait très facilement. (Merci de voter la réponse de sipwiz!)

IPEndPoint localpt = new IPEndPoint(IPAddress.Any, 6000);

//Failed try
    try
    {
        var u = new UdpClient(5000);
        u.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);

        UdpClient u2 = new UdpClient(5000);//KABOOM
        u2.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
    }
    catch (Exception)
    {
        Console.WriteLine("ERROR! You must call Bind only after setting SocketOptionName.ReuseAddress. \n And you must not pass any parameter to UdpClient's constructor or it will call Bind.");
    }

//This is how you do it (kudos to sipwiz)
    UdpClient udpServer = new UdpClient(localpt); //This is what the proprietary(see question) sender would do (nothing special) 

    //!!! The following 3 lines is what the poster needs...(and the definition of localpt (of course))
    UdpClient udpServer2 = new UdpClient();
    udpServer2.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
    udpServer2.Client.Bind(localpt);
33
Tarnay Kálmán

Vous pouvez vous connecter à un port plusieurs fois à l'aide de l'option de socket ReuseAddress. 

UdpClient udpClient = new UdpClient();
udpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);

Vous devez également définir la même option sur le socket du serveur UDP.

72
sipwiz

Voici le code complet des réponses de Tarnay Kálmán et sipwiz:

Le code du serveur:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;

namespace UdpBroadcastTest
{
    class Program
    {
        static void Main(string[] args)
        {

            Console.WriteLine("Sender");
            // This constructor arbitrarily assigns the local port number.

            UdpClient udpClient = new UdpClient();
            udpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
            udpClient.Connect("localhost", 11000);
            try
            {
                string message = String.Empty;
                do
                {
                    message = Console.ReadLine();
                    // Sends a message to the Host to which you have connected.
                    Byte[] sendBytes = Encoding.ASCII.GetBytes(message);

                    udpClient.Send(sendBytes, sendBytes.Length);
                } while (message != String.Empty);

                udpClient.Close();
            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
            }

            Console.WriteLine("Press Any Key to Continue");
            Console.ReadKey();
        }
    }
}

Le code client:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;

namespace UdpReciever
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Receiver");
            // This constructor arbitrarily assigns the local port number.
            UdpClient udpClient = new UdpClient();
            udpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
            udpClient.Client.Bind(new IPEndPoint(IPAddress.Any, 11000));
            try
            {
                //IPEndPoint object will allow us to read datagrams sent from any source.
                IPEndPoint RemoteIpEndPoint = new IPEndPoint(IPAddress.Any, 0);

                string message = String.Empty;
                do
                {

                    // Blocks until a message returns on this socket from a remote Host.
                    Byte[] receiveBytes = udpClient.Receive(ref RemoteIpEndPoint);
                    message = Encoding.ASCII.GetString(receiveBytes);

                    // Uses the IPEndPoint object to determine which of these two hosts responded.
                    Console.WriteLine("This is the message you received: " +
                                                 message);
                    //Console.WriteLine("This message was sent from " +
                    //                            RemoteIpEndPoint.Address.ToString() +
                    //                            " on their port number " +
                    //                            RemoteIpEndPoint.Port.ToString());
                }
                while (message != "exit");
                udpClient.Close();
                //udpClientB.Close();

            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
            }

            Console.WriteLine("Press Any Key to Continue");
            Console.ReadKey();
        }
    }
}
5
epotter

Vous pourrez peut-être mettre plusieurs adresses IP sur votre carte réseau ou boucler et lier le serveur et le client à différentes adresses IP?

Sinon, l’approche de la machine virtuelle fonctionnera définitivement.

2
Douglas Leeder

Un seul programme peut lier à un port à la fois. Plusieurs programmes peuvent se connecter à un port d'un autre système, mais le port local auquel vos différents navigateurs Web se sont liés est attribué de manière aléatoire.

À moins que vous ne vouliez faire une mauvaise communication entre processus ou un renifleur de paquets, il n’est pas possible d’avoir plusieurs programmes liés à un seul port.

1
rmmh

Mon conseil: ne transmettez pas le numéro de port au constructeur UdpClient. D'après la documentation , (un peu clairsemée, je sais ...), cela ressemble à cela, l'UdpClient essaiera de lier à ce port (qui, comme le fait sysrqb, n'est pas autorisé). (Si vous ne le faites pas, je pense que l'UdpClient écoutera toutes les réponses sur un port aléatoire. Vous pouvez également choisir un port que vous savez être inutilisé.) 

Lorsque vous appelez Connect (), vous devez indiquer le numéro de port du serveur listen.

0
mpontillo

Même en changeant votre code pour que je puisse transmettre une adresse IP, le même message d'erreur apparaît que vous ne pouvez pas vous connecter au même port et que vous ne pouvez utiliser qu'un seul port. et modifié pour capturer mon adresse IP à partir de ma machine locale .. IPAddress ipAddress = Dns.Resolve (Dns.GetHostName ()). AddressList [0]; IPEndPoint ipLocalEndPoint = new IPEndPoint (ipAddress, 11000);

        //IPEndPoint localpt = new IPEndPoint(ipLocalEndPoint);

        UdpClient udpServer = new UdpClient(ipLocalEndPoint);
        udpServer.Client.SetSocketOption(
            SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
        udpServer.Connect(ipLocalEndPoint);
        UdpClient udpServer2 = new UdpClient();
        udpServer2.Client.SetSocketOption(
            SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);

        udpServer2.Client.Bind(ipLocalEndPoint); // <<---------- Exception here

cela produira l'exception sur la méthode Bind () .. désolé.

0
MethodMan

lier les deux programmes, c’est-à-dire l’émetteur et le destinataire, au même port sur le localhost.dats la réponse simple.

0
saikat