10


9

Javaでスレッド化されたUDPベースのサーバーを実装する方法

基本的には、複数のクライアントをサーバーに接続し、各クライアントに独自のスレッドを持たせることが必要です。 唯一の問題は、クライアントがサーバーに接続しようとしているのかどうかを確認し、新しいスレッドを作成する方法がわからないことです。

boolean listening = true;

System.out.println( "サーバーが起動しました。");

新しいServerThread()の間に(リスニング)start();

この場合、サーバーはメモリーがなくなるまで新しいスレッドを生成します。 これがServerThreadのコードです(クライアントが接続を試みるまでServerThreadの作成を停止させるメカニズムが必要です)。

public ServerThread(String name)はIOException {super(name);}をスローします。 socket = new DatagramSocket(); }

だからJavaプログラミングの父親は助けてください。

4 Answer


14


ある程度これのための設計はそれぞれの完全なUDP "ダイアログ"がただ一つの要求と即時の応答を必要とするかどうか、それが単一の要求または再送信を伴う応答であるかどうか、あるいは多数のパケットを処理する必要があるかどうかに左右される各クライアント

私が書いたRADIUSサーバーは、シングルリクエストの再送信モデルを持っていて、入ってくるパケットごとにスレッドを生成しました。

`DatagramPacket`が受け取られるたびに、それは新しいスレッドに渡され、そしてそのスレッドは応答を送り返す責任があります。 これは、各応答の生成に関わる計算およびデータベースアクセスに比較的長い時間がかかり、古いパケットが処理されている間に到着する新しいパケットを処理するための他のメカニズムを使用するよりもスレッドの生成が簡単だからです。

public class Server implements Runnable {
    public void run() {
        while (true) {
            DatagramPacket packet = socket.receive();
            new Thread(new Responder(socket, packet)).start();
        }
    }
}

public class Responder implements Runnable {

    Socket socket = null;
    DatagramPacket packet = null;

    public Responder(Socket socket, DatagramPacket packet) {
        this.socket = socket;
        this.packet = packet;
    }

    public void run() {
        byte[] data = makeResponse(); // code not shown
        DatagramPacket response = new DatagramPacket(data, data.length,
            packet.getAddress(), packet.getPort());
        socket.send(response);
    }
}


6


UDPはコネクションレス型のプロトコルなので、各コネクションごとに新しいスレッドを生成する必要があるのはなぜですか? UDPパケットを受信したら、受信したメッセージを処理するために新しいスレッドを生成する必要があります。

UDP接続はTCP接続とは異なります。 それらはアクティブなままではなく、そのようなものがUDPの設計です。

この次のコードブロックのhandlePacket()メソッドは、受け取ったデータを使って必要なことをすべて実行できます。 そして多くのクライアントは同じUDPリスナーに複数のパケットを送ることができます。 多分それはあなたを助けるでしょう。

public void run(){DatagramSocket wSocket = null; DatagramPacket wPacket = null。 byte [] wBuffer = null;

{wSocket = new DatagramSocket(listenPort);}をお試しください。 wBuffer = new byte [2048]; wPacket = new DatagramPacket(wBuffer、wBuffer.length); } catch(SocketException e){log.fatal( "ソケットを開けませんでした:\ n" e.getMessage());}}。 System.exit(1); }

while(isRunning){try {wSocket.receive(wPacket);} handlePacket(wPacket、wBuffer); catch(例外e){log.error(e.getMessage());} }}}


3


http://mina.apache.org/[Apache Mina]プロジェクトを見ましたか? 私は、その例の1つでもそれを使ってUDPベースのサーバーを設定する方法を説明してくれると思います。 これが実際の製品のためのものであるなら、私はあなた自身の実装を一から考え出すことを試みることを勧めません。 これを実現するためにライブラリを使用したいので、接続ごとに1つのスレッドを使用するのではなく、スレッドプールを使用しないでください。


1


私は本当に必要性を見ません。

その学校のことは正しいですか?

クライアントを追跡する必要がある場合は、各クライアントのローカル表現(サーバー上のClientオブジェクト)が必要です。 それはあなたがする必要があるどんなクライアント特有の事の世話をすることもできます。

その場合は、どのクライアントからメッセージが送信されたのかを知ることができる必要があります。 (メッセージからの情報を使用します。)クライアントをマップに保持できます。

最も効果的な方法は、実行する必要があるものがすべて外部イベントの待機を「ブロック」できない場合(または発生するはずの処理に時間がかかり、非常に短い場合がない限り)、メインスレッドですべての処理を行うことです。 )

パブリッククラスClient {

public void handleMessage(Message m){//ここで何かをする。 }

}

必要ならば、クライアントオブジェクトはおそらくhandleMessage()で新しいスレッドを開始できます。

複数のサーバースレッドを起動しないでください。

サーバースレッドは次のことができます。

while(実行中){socket.receive(DatagramPacket p); client = figureOutClient(p); client.handleMessage(p); }

クライアント固有のことを気にする必要がない場合は、メッセージを読み、到着したときにそれらを1つのスレッドで処理するだけです。