15

スレッド化されたUDPベースのサーバーをJavaで実装するにはどうすればよいですか?

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

boolean listening = true;

System.out.println("Server started.");

while (listening)
    new ServerThread().start();

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

public ServerThread(String name) throws IOException 
{
    super(name);
    socket = new DatagramSocket();
}

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

4

4 に答える 4

18

このための設計は、各完全な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);
    }
}
于 2009-04-22T13:28:10.647 に答える
6

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

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

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

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

        try {
            wSocket = new DatagramSocket( listenPort );
            wBuffer = new byte[ 2048 ];
            wPacket = new DatagramPacket( wBuffer, wBuffer.length );
        } catch ( SocketException e ) {
            log.fatal( "Could not open the socket: \n" + e.getMessage() );
            System.exit( 1 );
        }

        while ( isRunning ) {
            try {
                wSocket.receive( wPacket );
                handlePacket( wPacket, wBuffer );
            } catch ( Exception e ) {
                log.error( e.getMessage() );
            }
        }
    }
于 2009-04-21T15:25:09.923 に答える
3

Apache Minaプロジェクトを見たことがありますか?その例の1つでも、UDPベースのサーバーをセットアップする方法を説明していると思います。これが実際の製品の場合、独自の実装を最初から考え出すことはお勧めしません。これを実現するためにライブラリを使用して、接続ごとに1つのスレッドを使用するのではなく、スレッドプールを使用することをお勧めします。

于 2009-04-21T15:29:54.933 に答える
1

私は本当にその必要性を理解していません。

それは学校のことでしょ?

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

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

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

public class Client {

    public void handleMessage(Message m) {
    // do stuff here.
    }

}

クライアントオブジェクトは、必要に応じて、handleMessage()で新しいスレッドを開始できる可能性があります。

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

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

while(running) {
  socket.receive(DatagramPacket p);
  client = figureOutClient(p);
  client.handleMessage(p);
}

クライアント固有の注意事項がない場合は、メッセージを読んで、到着したメッセージを1つのスレッドで処理するだけです。

于 2009-04-21T15:44:22.730 に答える