指定したポートでサーバーを常にリッスンする必要があります。サーバーがそのポートでの着信接続を認識したら、そのクライアントとサーバー間の通信を処理する新しいスレッドを作成する必要がありますが、メイン スレッドは他の着信接続をリッスンし続けます。このようにして、複数のクライアントを 1 つのサーバーに接続できます。そのようです:
private void listen() throws IOException {
serverSocket = new ServerSocket(port)
while (GlobalFlags.listening) {
new ServerThread(serverSocket.accept();
if (GlobalFlags.exit) {
serverSocket.close();
break;
}
}
}
GlobalFlags はリスニング プロセスを制御するための変数であり、実際には必要ありません。あなたはしばらくTrueを行い、ただずっと聞き続けることができます.
私のプロジェクトでは、スレッドで実行されているリスナーを持つメイン サーバー コントローラーがあります。コントローラは GlobalFlags を制御しました。グローバルフラグを使用する代わりに、スレッド間通信を行うためのより良い方法があると確信していますが、私にとってはこれが当時最も簡単でした。
ServerThread は、クライアントへの出力の送信とクライアントからの入力の受信を切り替えながら常にループしている必要があります。そのようです:
ServerThread(Socket socket) {
super("GameServerThread");
this.socket = socket;
try {
this.socket.setTcpNoDelay(true);
} catch (SocketException e) {
// Error handling
}
this.terminate = false;
}
@Override
public void run() {
try {
out = new PrintWriter(socket.getOutputStream(), true);
in = new BufferedReader(
new InputStreamReader(
socket.getInputStream()));
String inputLine, outputLine;
while ((inputLine = in.readLine()) != null) {
outputLine = processInput(inputLine);
out.println(outputLine);
if (terminate) {
break;
}
}
}
out.close();
in.close();
socket.close();
} catch (Exception e) {
// Error handling, should not use Exception but handle all exceptions by themselves.
}
クライアント側では、同様のループを実行するスレッドがあり、サーバーから入力を受け取り、サーバーに出力を送信します。
この例では、processInput はクライアントの入力を処理するために使用される関数です。サーバーに接続を開始させたい場合は、入力をリッスンする前にサーバーに何かを出力ストリームに送信させ、クライアントに最初にリッスンさせることができます。
私は自分のプロジェクトの 1 つからこの例を抽出しました。 this.socket.setTcpNoDelay(true) はプロセスを高速化するはずです。ここを参照してください: http://www.rgagnon.com/javadetails/java-0294.html
"java.net.Socket.setTcpNoDelay() は、TCP_NODELAY を有効/無効にするために使用され、Nagle のアルゴリズムを無効/有効にします。Nagle のアルゴリズムは、送信されるセグメントの数を最小限に抑えることで帯域幅を節約しようとします。アプリケーションがネットワークの遅延を減らし、パフォーマンスを向上させたい場合, 彼らはNagleのアルゴリズムを無効にすることができます.
java.net.Socket.getTcpNoDelay() を使用して、現在の「TCP_NODELAY」設定を取得します。
したがって、特定のクライアントにメッセージを送信するには、作成時にすべてのスレッドを ArrayList に入れることができるため、現在接続されているすべてのクライアントを追跡できます。別のクラスが送信するメッセージをキュー/変数に入れるまで、processInput メソッドを停止してキュー/変数をポーリングすることができます。したがって、クラスのハンドルを取得する方法は、processInput の実装によって異なります。すべてのスレッドに ID を与えることができ (これは私のプロジェクトで行ったことです)、おそらく processInput メソッドに index=ID の ArrayList をポーリングさせることができます。次に、出力をクライアントに送信するには、変数を index=ID に設定する必要があります。
この方法は個人的にはちょっと不格好に思えますが、他にどのようにすればよいかわかりません。おそらくキューを使用し、processInput に入力をそのキューに書き込んでもらい、別のクラスがそれを読み取ってその応答をキューに入れるのを待ちます。しかし、私は個人的に Java でキューを扱ったことがないので、自分で読んでください。