38

同じポート番号を共有することにより、2 つの別々のプログラムが同じコンピューター上で (一方向のみ) localhost/127 を介して UDP 経由で通信することは可能ですか?

私たちは、2 台のコンピューター間でテレメトリを含む UDP パケットを送信する必要がある学生プロジェクトに取り組んでいます。これらのパケットを生成するプログラムは独自のものですが、 System.Net.Sockets.UdpClientSystem.Net.IPEndPointを使用して C# で受信プログラムを自分で作成しています。

これは、2 つのプログラムを別々に実行できる複数のコンピューターが接続されている場合、グループのミーティング中に問題なく機能します。しかし、家にいてテレメトリ処理プログラムを拡張しようとしているときは、コンピューターが 1 台しかないため、あまり役に立ちません (処理プログラムをテストするためのフィードが必要です)。学校のどのコンピュータにもプログラムをインストールできません。

コンピューターで両方のプログラムを同時に実行しようとすると (プログラムを最後に開始して)、通常は各ポートの 1 回の使用のみが許可されていることを示す SocketException が発生します。これは、ポートを共有する何らかの方法があるに違いないと私に信じさせます (一度に 1 つのプログラムだけがコンピューター上のポートを使用できることは理にかなっていますが、同時に複数のインターネット ブラウザーを実行しても問題はありません (そして私はhttp にポート 80 を使用するとします)))。

編集の再編集:

sipwiz は正しかったです。UdpClient.Client.Bind() へのポインタを提供してくれた Kalmi に感謝します。ただし、現時点では、同様のパケットを生成する別のプログラムを使用することを検討しており、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

一度にポートにバインドできるプログラムは 1 つだけです。複数のプログラムが別のシステムの 1 つのポートに接続できますが、さまざまな Web ブラウザーがバインドされているローカル ポートはランダムに割り当てられます。

醜いプロセス間通信やパケット スニッフィングを行いたくない場合を除き、複数のプログラムを 1 つのポートにバインドする方法はありません。

于 2009-03-26T22:58:53.517 に答える
1

IPアドレスを渡すことができるようにコードを変更しても、同じエラーメッセージが表示されます。同じポートにバインドできず、ここで使用できるポートは1つだけのようです。サンプルコードは、あなたの例を使用して変更しましたローカル マシンから IP を取得するには.. IPAddress ipAddress = Dns.Resolve(Dns.GetHostName()).AddressList[0]; IPEndPoint ipLocalEndPoint = 新しい 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

2つのプログラム、つまり送信者と受信者をlocalhost.datsの同じポートにバインドします。簡単な答えです。

于 2009-08-02T09:40:53.823 に答える