是否可以通过localhost/127 ...通过共享相同的端口#来获得两个独立的程序在同一台计算机上进行通信(仅限单向)
我们正在开展一个学生项目,我们需要在两台计算机之间发送包含遥测数据的UDP数据包.生成这些数据包的程序是专有的,但我正在使用System.Net.Sockets.UdpClient和System.Net.IPEndPoint使用C#编写接收程序.
在我们小组的会议期间,当我们连接多台计算机时,我们可以分别运行这两个程序.但是,当我回家并试图扩展遥测处理程序时它并不是很有用,因为我只有一台计算机(我需要一个用于测试处理程序的源程序).我也无法在学校的任何一台计算机上安装该程序.
当我尝试同时在我的计算机上运行这两个程序(最后开始我的程序)时,我得到一个SocketException,说通常只允许使用每个端口.这让我相信必须有一些方法来共享端口(虽然任何时候只有一个程序可以在计算机上使用端口是有意义的,我同时运行多个互联网浏览器没有问题(我假设他们使用端口80作为http)).
编辑的REEDIT:
sipwiz是对的,感谢Kalmi指向UdpClient.Client.Bind()的指针.但是,当时我们正在考虑使用另一个生成类似数据包的程序,并且我们可以使用我的第一个(虽然天真)方法在ctor中使用UDP客户端绑定在同一台计算机上共享端口.抱歉,您必须取消标记您的答案,sysrqb.
您可以使用ReuseAddress套接字选项多次绑定到端口.
UdpClient udpClient = new UdpClient(); udpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
您还需要在UDP服务器套接字上设置相同的选项.
我没想到这是可能的,但是..好吧.. 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);
以下是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(); } } }