41

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.

Cecil Has a Name
  • 4,962
  • 1
  • 29
  • 31
  • One way you could potentially get around this if no other solution is available is to create a virtual machine and have the virtual machine communicate with your main desktop. – TheTXI Mar 26 '09 at 22:58
  • Internet browsers don't share ports. They use a random port(assigned by the OS) to connect to the server. The client's and the server's port don't have to be the same. Use netstat to see what ports your browsers are using. – Tarnay Kálmán Mar 27 '09 at 01:34

8 Answers8

84

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.

Mark Heath
  • 48,273
  • 29
  • 137
  • 194
sipsorcery
  • 30,273
  • 24
  • 104
  • 155
  • The ReuseAddress property is used to enable a server application to listen for connections using the specified address and port number even if they were in use recently. This is used to enable the server to close the listening socket and immediately reopen it without getting an error. – Tarnay Kálmán Mar 27 '09 at 01:43
  • And he wants to bind to the same port twice... So ReuseAddress is not relevant. – Tarnay Kálmán Mar 27 '09 at 01:47
  • Thats incorrect. ReuseAddress means exactly what it says with no conditions about whether the socket is a server or a client. If you want to reuse a port on one socket for SENDING and on one for RECEIVING you can. – sipsorcery Mar 27 '09 at 03:29
  • "Vote too old to be changed, unless post is edited"... doh... PLease edit the question so that I can vote you up. – Tarnay Kálmán Mar 27 '09 at 21:54
  • sipwiz' original proposal works if you just add the statement udpClient.Client.Bind(localpt); – Cecil Has a Name Mar 27 '09 at 23:47
  • Wonderful. I'd tried setting ExclusiveAddressUse to false w/out luck and almost gave up. Once again SO to the rescue. – Walden Leverich Apr 07 '09 at 19:29
39

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);
Tarnay Kálmán
  • 6,907
  • 5
  • 46
  • 57
  • I'll look into it. Currently we have switched to another program which apparantly allows us to send and receive on the same computer "out of the box", while we can also control that program more easily. So thanks to sipwiz! – Cecil Has a Name Mar 27 '09 at 23:18
5

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();
        }
    }
}
epotter
  • 7,631
  • 7
  • 63
  • 88
  • Hi, what if both applications are sender and received, as i understand from this example it will only work on same machine if one is only sender and other is only receiver? – Scavs Jun 21 '17 at 02:37
  • 1
    You've got your examples mislabelled (sender should be "client" and receiver should be "server"). – Mud Aug 14 '17 at 00:02
2

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.

Douglas Leeder
  • 52,368
  • 9
  • 94
  • 137
1

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.

rmmh
  • 6,997
  • 26
  • 37
1

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

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

MethodMan
  • 18,625
  • 6
  • 34
  • 52
0

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

0

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

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

mpontillo
  • 13,559
  • 7
  • 62
  • 90
  • "The program that generates these packets is proprietary" and the problem is that it is binding to the same port it is sending to. – Tarnay Kálmán Mar 27 '09 at 01:37