Подтвердить что ты не робот

Отправка и получение пакетов UDP между двумя программами на одном компьютере

Можно ли получить две отдельные программы для обмена данными на одном компьютере (только с одним движением) через UDP через localhost/127... путем совместного использования одного и того же порта #?

Мы работаем над студенческим проектом, в котором нам нужно отправить UDP-пакеты, содержащие некоторую телеметрию между двумя компьютерами. Программа, генерирующая эти пакеты, является проприетарной, но я сама работаю над программой-получателем с С#, используя System.Net.Sockets.UdpClient и System.Net.IPEndPoint.

Это прекрасно работает во время наших групповых встреч, когда у нас есть несколько компьютеров, на которых мы можем запускать две программы отдельно. Но это не очень полезно, когда я дома и пытаюсь расширить программу обработки телеметрии, поскольку у меня только один компьютер (мне нужен фид для тестирования программы обработки). Я не могу установить программу на любом из школьных компьютеров.

Когда я пытаюсь запустить обе программы на своем компьютере в одно и то же время (начиная с последней моей программы), я получаю SocketException, говорящий, что разрешено только одно использование каждого порта. Это заставляет меня поверить, что какой-то способ обмена портом должен быть каким-то образом (хотя имеет смысл, что только одна программа может использовать порт на компьютере в любой момент времени, у меня нет проблем с одновременным запуском нескольких интернет-браузеров (и я предположим, что они используют порт 80 для http)).

REEDIT EDIT:

sipwiz был прав, и благодаря Kalmi для указателя на UdpClient.Client.Bind(). В то же время мы рассматриваем возможность использования другой программы, которая генерирует аналогичные пакеты и с которыми мы можем обмениваться портами на одном компьютере, используя мой первый (хотя и наивный) подход с привязкой клиента UDP в ctor. Извините за отмену ответа, sysrqb.

4b9b3361

Ответ 1

Я не ожидал, что это будет возможно, но.. хорошо.. sipwiz был прав.

Это можно сделать очень легко. (Пожалуйста, проголосуйте за ответ 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 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);

Ответ 2

Вы можете связываться с портом несколько раз, используя опцию сокета ReuseAddress.

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

Вам также нужно установить ту же опцию на сокет сервера UDP.

Ответ 3

Возможно, вы можете разместить несколько IP-адресов на своей сетевой карте или loopback и связать сервер и клиент с разными IP-адресами?

Или иначе подход виртуальной машины определенно будет работать.

Ответ 4

Вот полный код из ответов Тарная Кальмана и сипвиза:

Код сервера:

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

Код клиента:

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

Только одна программа может привязываться к порту за раз. Несколько программ могут подключаться к одному порту на другой системе, но локальный порт, к которому привязаны другие веб-браузеры, назначается случайным образом.

Если вы не хотите совершать некоторую уродливую межпроцессную коммуникацию или обнюхивание пакетов, нет способа иметь несколько программ, связанных с одним портом.

Ответ 6

Мой совет: не передавать номер порта в конструктор UdpClient. Из документации (несколько разреженный, я знаю...) похоже, что если вы это сделаете, UdpClient попытается связать этот порт (что, как указано в sysrqb, не допускается). (Если вы этого не сделаете, я считаю, что UdpClient будет прослушивать случайный порт для любых ответов. Вы также можете выбрать порт, который, как вы знаете, не использовался.)

Когда вы вызываете Connect(), вам необходимо передать номер порта, который прослушивает сервер.

Ответ 7

свяжите две программы, то есть отправитель и получатель с одним и тем же портом на localhost.dats, простой ответ.

Ответ 8

Даже изменяя свой код, чтобы я мог передавать IP-адрес, я получаю такое же сообщение об ошибке, что кажется, что вы не можете привязываться к одному и тому же порту, и можно использовать только один порт вот пример кода Я использовал ваш пример и изменил его, чтобы захватить мой ip с моей локальной машины..             IPAddress ipAddress = Dns.Resolve(Dns.GetHostName()). AddressList [0];           IPEndPoint ipLocalEndPoint = новый 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

это приведет к исключению в методе Bind(). извините.