在同一台计算机上的两个程序之间发送和接收UDP数据包

时间:2022-07-27 18:10:26

Is it possible to get two separate programs to communicate on the same computer (one-way only) over UDP through localhost/127... by sharing the same port #?

是否有可能通过localhost / 127 ...通过共享相同的端口来获得两个独立的程序在同一台计算机上进行通信(仅限单向)

We're working on a student project in which we need to send UDP packets containing some telemetry between two computers. The program that generates these packets is proprietary, but I'm working on the receiver program myself with C# using System.Net.Sockets.UdpClient and System.Net.IPEndPoint.

我们正在开展一个学生项目,我们需要在两台计算机之间发送包含遥测数据的UDP数据包。生成这些数据包的程序是专有的,但我正在使用System.Net.Sockets.UdpClient和System.Net.IPEndPoint使用C#编写接收程序。

This works fine during our group's meetings when we have multiple computers connected on which we can run the two programs separately. But it's not very useful when I'm home and trying to expand on the telemetry processing program as I only have one computer (I need a feed for testing the processing program). I can not install the program on any of the school's computers either.

在我们小组的会议期间,当我们连接多台计算机时,我们可以分别运行这两个程序。但是,当我回家并试图扩展遥测处理程序时它并不是很有用,因为我只有一台计算机(我需要一个用于测试处理程序的源)。我无法在任何学校的计算机上安装该程序。

When I try to run both programs on my computer at the same time (starting my program last) I get a SocketException saying that only a single use of each port is normally allowed. Which leads me to believe there must be some way to share the port (although it makes sense that only a single program can use port on a computer at any one time, I have no trouble running multiple internet browsers at the same time (and I suppose they use port 80 for http)).

当我尝试同时在我的计算机上运行这两个程序时(最后开始我的程序),我得到一个SocketException,说通常只允许一次使用每个端口。这让我相信必须有一些方法来共享端口(虽然任何时候只有一个程序可以在计算机上使用端口是有意义的,我同时运行多个互联网浏览器没有问题(我假设他们使用端口80作为http))。

REEDIT of the EDIT:

编辑的REEDIT:

sipwiz was right, and thanks to Kalmi for the pointer to UdpClient.Client.Bind(). At the time, though, we are considering using another program that generates similar packets, and with which we are able to share port with on the same computer using my first (although naive) approach with the UDP client binding in the ctor. Sorry for having to unmark your answer, sysrqb.

sipwiz是对的,感谢Kalmi指向UdpClient.Client.Bind()的指针。但是,当时我们正在考虑使用另一个生成类似数据包的程序,并且我们可以使用我的第一个(虽然天真)方法在ctor中使用UDP客户端绑定在同一台计算机上共享端口。很抱歉不得不取消标记你的答案,sysrqb。

8 个解决方案

#1


I did not expect this to be possible, but.. well.. sipwiz was right.

我没想到这是可能的,但是..好吧.. sipwiz是对的。

It can be done very easily. (Please vote sipwiz's answer up!)

它可以很容易地完成。 (请投票给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);

#2


You can bind to a port multiple times using the ReuseAddress socket option.

您可以使用ReuseAddress套接字选项多次绑定到端口。

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

You'll need to set the same option on the UDP server socket as well.

您还需要在UDP服务器套接字上设置相同的选项。

#3


Here is the full code from the answers by Tarnay Kálmán and sipwiz:

以下是TarnayKálmán和sipwiz答案的完整代码:

The server code:

服务器代码:

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

The client code:

客户端代码:

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

#4


You might be able to put multiple IP addresses on your network card, or loopback, and bind the server and client to different IP addresses?

您可以在网卡上放置多个IP地址,或者环回,并将服务器和客户端绑定到不同的IP地址?

Or else the Virtual machine approach will definitely work.

否则虚拟机方法肯定会起作用。

#5


Only one program can bind to a port at a time. Multiple programs can connect to one port on another system's, but the local port your different web browsers have bound themselves to is randomly assigned.

一次只能有一个程序绑定到一个端口。多个程序可以连接到另一个系统上的一个端口,但是不同Web浏览器绑定的本地端口是随机分配的。

Unless you want to do some ugly inter-process communication or packet sniffing, there's no way to have multiple programs bound to one port.

除非您想进行一些丑陋的进程间通信或数据包嗅探,否则无法将多个程序绑定到一个端口。

#6


My advice: don't pass the port number into the UdpClient constructor. From the documentation, (somewhat sparse, I know...) it looks like if you do, the UdpClient will try to bind to that port (which, as sysrqb mentioned, is not allowed). (If you don't, I believe the UdpClient will listen on a random port for any replies. You could also pick a port you know to be unused.)

我的建议:不要将端口号传递给UdpClient构造函数。从文档中,(有点稀疏,我知道......)看起来如果你这样做,UdpClient将尝试绑定到该端口(如sysrqb所述,不允许)。 (如果你不这样做,我相信UdpClient会在随机端口上收听任何回复。你也可以选择一个你知道未使用的端口。)

When you call Connect() you need to pass in the port number the server is listening on.

当您调用Connect()时,您需要传入服务器正在侦听的端口号。

#7


bind the two programs,ie, the sender and receiver to the same port on the localhost.dats the simple answer.

绑定两个程序,即发送方和接收方到localhost.dats上的同一个端口简单的答案。

#8


Even changing your code so that I can pass in an IP address I gets the same error message it appears that you can't bind to the same port and only one port can be used here is the sample code I used your example and Altered it to capture my ip from my local machine.. IPAddress ipAddress = Dns.Resolve(Dns.GetHostName()).AddressList[0]; IPEndPoint ipLocalEndPoint = new IPEndPoint(ipAddress, 11000);

即使更改你的代码,以便我可以传入一个IP地址我得到相同的错误消息,看起来你不能绑定到同一个端口,这里只能使用一个端口是我用你的例子和改变它的示例代码从我的本地机器捕获我的IP .. 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

this will produce the exception on the Bind () method.. sorry.

这会在Bind()方法上产生异常..抱歉。

#1


I did not expect this to be possible, but.. well.. sipwiz was right.

我没想到这是可能的,但是..好吧.. sipwiz是对的。

It can be done very easily. (Please vote sipwiz's answer up!)

它可以很容易地完成。 (请投票给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);

#2


You can bind to a port multiple times using the ReuseAddress socket option.

您可以使用ReuseAddress套接字选项多次绑定到端口。

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

You'll need to set the same option on the UDP server socket as well.

您还需要在UDP服务器套接字上设置相同的选项。

#3


Here is the full code from the answers by Tarnay Kálmán and sipwiz:

以下是TarnayKálmán和sipwiz答案的完整代码:

The server code:

服务器代码:

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

The client code:

客户端代码:

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

#4


You might be able to put multiple IP addresses on your network card, or loopback, and bind the server and client to different IP addresses?

您可以在网卡上放置多个IP地址,或者环回,并将服务器和客户端绑定到不同的IP地址?

Or else the Virtual machine approach will definitely work.

否则虚拟机方法肯定会起作用。

#5


Only one program can bind to a port at a time. Multiple programs can connect to one port on another system's, but the local port your different web browsers have bound themselves to is randomly assigned.

一次只能有一个程序绑定到一个端口。多个程序可以连接到另一个系统上的一个端口,但是不同Web浏览器绑定的本地端口是随机分配的。

Unless you want to do some ugly inter-process communication or packet sniffing, there's no way to have multiple programs bound to one port.

除非您想进行一些丑陋的进程间通信或数据包嗅探,否则无法将多个程序绑定到一个端口。

#6


My advice: don't pass the port number into the UdpClient constructor. From the documentation, (somewhat sparse, I know...) it looks like if you do, the UdpClient will try to bind to that port (which, as sysrqb mentioned, is not allowed). (If you don't, I believe the UdpClient will listen on a random port for any replies. You could also pick a port you know to be unused.)

我的建议:不要将端口号传递给UdpClient构造函数。从文档中,(有点稀疏,我知道......)看起来如果你这样做,UdpClient将尝试绑定到该端口(如sysrqb所述,不允许)。 (如果你不这样做,我相信UdpClient会在随机端口上收听任何回复。你也可以选择一个你知道未使用的端口。)

When you call Connect() you need to pass in the port number the server is listening on.

当您调用Connect()时,您需要传入服务器正在侦听的端口号。

#7


bind the two programs,ie, the sender and receiver to the same port on the localhost.dats the simple answer.

绑定两个程序,即发送方和接收方到localhost.dats上的同一个端口简单的答案。

#8


Even changing your code so that I can pass in an IP address I gets the same error message it appears that you can't bind to the same port and only one port can be used here is the sample code I used your example and Altered it to capture my ip from my local machine.. IPAddress ipAddress = Dns.Resolve(Dns.GetHostName()).AddressList[0]; IPEndPoint ipLocalEndPoint = new IPEndPoint(ipAddress, 11000);

即使更改你的代码,以便我可以传入一个IP地址我得到相同的错误消息,看起来你不能绑定到同一个端口,这里只能使用一个端口是我用你的例子和改变它的示例代码从我的本地机器捕获我的IP .. 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

this will produce the exception on the Bind () method.. sorry.

这会在Bind()方法上产生异常..抱歉。