私は3つのメインクラスを含む動作中のJavaサーバーを持っています(端が少し荒いですが)。
最初のクラスはサーバーを実行し、ソケットを取得してポートをリッスンし、新しい接続をクライアント ハンドラーに渡します。
2 番目のクラスは、スレッド化されたクライアント ハンドラーです。
3 つ目は、クライアント ハンドラから呼び出されて情報を処理するプロトコル クラスです。情報が処理されると、プロトコル クラスは処理済みまたはフォーマット済みの応答をクライアント ハンドラーに返し、クライアントに渡します。
利点は、2 番目のクラスに、ソケットから受け入れ可能なデータをロードするだけでよいことです。データはプロトコル ハンドラに渡すことができ、プロトコル ハンドラには、サーバーがクライアントと通信するために使用する任意のプロトコルをロードできます。
この例では、telnet ベースのチャット クラスをロードしました。
たとえば、誰かがチャットを離れた場合、クライアント ハンドラ クラスは次のようなコードを実行する可能性があります。
for (i = 0; i < currentClientsConnected; i++) {
if(threads[i] != null && threads[i] != this) {
outputLine = threads[i].serverprotocol.processInput("** " + username + " has left the room **");
threads[i].out.printf(outputLine);
}
}
これはクラスに渡さ"** [username] has left the room **"
れ、serverprotocol
クラスはメッセージをクライアントに送信するための最適な方法でデータを返します。この場合、serverprotocol
クラスはクライアントに画面を再描画し、新しいメッセージを追加し、バッファ内の既存の現在のメッセージを上にスクロールするように指示する telnet 制御コードを使用してメッセージをフォーマットします。
また、クライアント ハンドラー クラスは、たとえばユーザーが特定のチャット ルームにいるソケットにのみメッセージを送信する必要があるため、常にすべてのソケットに送信する必要はありません。
私のコードでは、これはクラス 1 です。ソケットを受け入れるサーバー クラスは次のとおりです。
while (true) {
int i;
// Try and accept the connection
try {
clientSocket = serverSocket.accept();
// System.out.printf("Remote IP:");
// System.out.printf(clientSocket.getRemoteSocketAddress().toString());
// Find an unused socket if one is available
for (i = 0; i < maxClientsAllowed; i++) {
// If found create thread
if (threads[i] == null) {
(threads[i] = new clientThread(clientSocket, threads)).start();
break;
}
}
// If all sockets are taken
if (i == maxClientsAllowed) {
PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true);
out.printf("Server too busy. Try later.\n");
out.close();
clientSocket.close();
}
} catch(IOException e) {
System.out.println(e);}
}
クラス 2 は、スレッドを拡張するクラスです。
class clientThread extends Thread {
private String clientName = null;
private DataInputStream in;
private PrintWriter out;
private Socket clientSocket = null;
private final clientThread[] threads;
private int currentClientsConnected;
private serverprotocol serverprotocol;
public clientThread(Socket clientSocket, clientThread[] threads) {
this.clientSocket = clientSocket;
this.threads = threads;
currentClientsConnected = threads.length;
}
public void run() {
//stuff
}
}
代わりにこれを機能させることができるかどうかを必死に確認しようとしましたが、スレッドのインスタンス番号に基づいてスレッドの(またはおそらくそれを読み取る必要がある) メソッドをimplements Runnable
呼び出すことができませんでした (ここのコードで単に呼び出されます)。 .processInput
dataToBeProcessed
i
私が見た中で最も近いもの:
これは、サーバーをスレッド化されたプール サーバーとして実行する際に利用できます。
ただし、この場合の関数は、 を介してソケットに関連付けられた にsendToAll
直接書き込みます。サーバーでは、個々のプロトコル ハンドラー クラスに送信することはできません。また、個々のクラス インスタンスに送信することもできません。これは、たとえば、メッセージをソケット 1 と 3 のみに送信してから、別のメッセージをソケット 2 に送信できないことを意味します。PrintWriter
HashMap
ChatServerWorker
を使用せずにソケットハンドラーのインスタンスを呼び出すことができるオンラインの例が1つも見つかりませんextends Thread
。
具体的には、次のような行を使用できるようにしたいと考えています。
threads[i].out.printf(outputLine);
また
if(threads[i].[class].[var] == 'something') {
// stuff
}
整数を使用して、スレッド インスタンス、またはそのスレッドで使用される任意のクラス変数またはメソッドを参照できます。
何か不足していますか?