是否可以通过localhost / 127通过共享相同的端口来获得两个独立的程序在同一台计算机上进行通信(仅限单向)
我们正在开展一个学生项目,我们需要在两台计算机之间发送包含遥测数据的UDP数据包。生成这些数据包的程序是专有的,但我正在使用 System.Net.Sockets.UdpClient 和 System.Net.IPEndPoint 在C#上使用C#编写接收程序。
在我们小组的会议期间,当我们连接多台计算机时,我们可以分别运行这两个程序。但是,当我回家并试图扩展遥测处理程序时它并不是很有用,因为我只有一台计算机(我需要一个用于测试处理程序的源程序)。我无法在任何学校的计算机上安装该程序。
当我尝试同时在我的计算机上运行这两个程序时(最后开始我的程序),我得到一个SocketException,说只允许一次使用每个端口 。这让我相信必须有一些方法来共享端口(虽然任何时候只有一个程序可以在计算机上使用端口是有意义的,我同时运行多个互联网浏览器没有问题(我假设他们使用端口80作为http))。
编辑的REEDIT:
sipwiz是对的,感谢Kalmi指向UdpClient.Client.Bind()的指针。 但是,当时我们正在考虑使用另一个生成类似数据包的程序,并且我们可以使用我的第一个(虽然天真)方法在ctor中使用UDP客户端绑定在同一台计算机上共享端口。 很抱歉不得不取消标记你的答案,sysrqb。
答案 0 :(得分:75)
您可以使用ReuseAddress套接字选项多次绑定到端口。
UdpClient udpClient = new UdpClient();
udpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
您还需要在UDP服务器套接字上设置相同的选项。
答案 1 :(得分:34)
我没想到这是可能的,但是......好吧...... 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);
答案 2 :(得分:5)
以下是TarnayKá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();
}
}
}
答案 3 :(得分:2)
您可以在网卡上放置多个IP地址,或者环回,并将服务器和客户端绑定到不同的IP地址?
否则虚拟机方法肯定会有用。
答案 4 :(得分:1)
一次只能有一个程序绑定到一个端口。多个程序可以连接到另一个系统的一个端口,但是不同的Web浏览器绑定的本地端口是随机分配的。
除非您想进行一些丑陋的进程间通信或数据包嗅探,否则无法将多个程序绑定到一个端口。
答案 5 :(得分:0)
我的建议:不要将端口号传递给UdpClient构造函数。从documentation,(有点稀疏,我知道......)看起来如果你这样做,UdpClient将尝试绑定到该端口(正如sysrqb所提到的那样)允许)。 (如果你不这样做,我相信UdpClient会在随机端口上收听任何回复。你也可以选择一个你知道不用的端口。)
当您致电Connect()时,您需要传入服务器收听的端口号。
答案 6 :(得分:0)
将两个程序绑定,即发送方和接收方绑定到localhost.dats上的同一个端口。简单的答案。
答案 7 :(得分:0)
即使更改代码以便我可以传入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()方法上产生异常..抱歉。