38

是否可以通过 localhost/127 让两个单独的程序在同一台计算机上通过 UDP 进行通信(仅单向)...通过共享相同的端口#?

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

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

当我尝试同时在我的计算机上运行这两个程序时(最后启动我的程序),我收到一个 SocketException,说通常只允许使用每个端口一次。这使我相信必须有某种方法来共享端口(尽管在任何时候只有一个程序可以使用计算机上的端口是有道理的,但我同时运行多个互联网浏览器没有问题(而且我假设他们将端口 80 用于 http))。

重新编辑编辑:

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

4

8 回答 8

80

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

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

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

于 2009-03-26T23:08:04.007 回答
38

我没想到这是可能的,但是.. 好吧.. 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'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);
于 2009-03-27T21:52:59.640 回答
5

以下是 Tarnay Kálmán 和 sipwiz 回答的完整代码:

服务器代码:

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();
        }
    }
}
于 2014-10-29T16:49:49.887 回答
2

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

否则虚拟机方法肯定会奏效。

于 2009-03-26T23:11:48.867 回答
1

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

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

于 2009-03-26T22:58:53.517 回答
1

即使更改您的代码以便我可以传递一个 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

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

于 2012-02-02T22:30:04.853 回答
0

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

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

于 2009-03-27T00:24:21.487 回答
0

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

于 2009-08-02T09:40:53.823 回答