在同一台計算機上的兩個程序之間發送和接收 UDP 數據包 (Sending and receiving UDP packets between two programs on the same computer)


問題描述

在同一台計算機上的兩個程序之間發送和接收 UDP 數據包 (Sending and receiving UDP packets between two programs on the same computer)

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 #?  

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

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)).

REEDIT of the EDIT:

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.


參考解法

方法 1:

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

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.

方法 2:

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

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

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

方法 3:

Here is the full code from the answers by Tarnay Kálmán and 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?

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.

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.

(by Cecil Has a NamesipsorceryTarnay KálmánepotterDouglas Leederrmmh)

參考文件

  1. Sending and receiving UDP packets between two programs on the same computer (CC BY-SA 3.0/4.0)

#port #localhost #UDP #C#






相關問題

使用java應用程序在linux中打開端口 (Open port in linux with java application)

如何在linux中了解特定端口的流量 (How to know traffic to a specific port in linux)

HDMI 連接不發送 WM_DEVICE_ARRIVAL 消息 (HDMI Connection Does Not Send WM_DEVICE_ARRIVAL Message)

移植安卓4.2 (Port android 4.2)

如何等到服務器上線才能訪問 REST API (How to wait till a server goes online to access a REST API)

與 apache 網絡服務器和 Node.js REST 服務器共享 HTTP 端口 80 (Share HTTP port 80 with apache webserver and Node.js REST server)

lighttpd:身份驗證後如何將端口(僅對本地主機可見)轉發到 WAN? (lighttpd: How to forward port (visible only to localhost) to WAN after authentication?)

通過警報端口重定向所有程序數據包 (Redirect all program packets through alerternate port)

在同一台計算機上的兩個程序之間發送和接收 UDP 數據包 (Sending and receiving UDP packets between two programs on the same computer)

是否可以更改 WAMP 調用的 url? (Is it possible to change the url called by WAMP?)

ServerSelectionTimeoutError:documentdb.documents.azure.com:10255:超時 (ServerSelectionTimeoutError: documentdb.documents.azure.com:10255: timed out)

kubernetes 正在暴露未聲明的端口 (kubernetes is exposing not declared port)







留言討論