私は本当にTCPソケット通信の背後にある理論の多くを知りませんが、実際の外に、私は次のコードを達成した:1つのクライアントが接続を失った後にTCPサーバーソケットが閉じられるのはなぜですか?
サーバー:
public class Server {
public static volatile ArrayList<ReplyThread> connections = new ArrayList<>();
public static void main(String[] args) {
new AcceptThread().start();
}
private static class AcceptThread extends Thread {
@Override
public void run() {
ServerSocket inSock;
try {
inSock = new ServerSocket(3074);
boolean loop = true;
while(loop) {
System.out.println("waiting for next connection");
connections.add(new ReplyThread(inSock.accept()));
System.out.println("connection made");
connections.get(connections.size() - 1).setName(""+(connections.size() - 1));
connections.get(connections.size() - 1).start();
}
inSock.close();
} catch (IOException ex) {
System.out.println(ex.getMessage());
}
}
}
public static class ReplyThread extends Thread {
private static Socket sock;
private DataOutputStream out;
public ReplyThread(Socket newSock) {
sock = newSock;
}
@Override
public void run() {
try {
DataInputStream in = new DataInputStream(sock.getInputStream());
out = new DataOutputStream(sock.getOutputStream());
boolean loop = true;
while(loop) {
String msg = in.readUTF();
System.out.println(msg);
for (ReplyThread thread : connections) {
thread.output(sock, msg);
}
}
in.close();
} catch (SocketException ex) {
Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
System.out.println("Connection terminated.");
this.interrupt();
System.out.println(this.getName() + " I was interrupted");
} catch (IOException ex) {
Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
}
}
public final void output(Socket sock, String message) throws IOException {
this.out.writeUTF(this.getName() + ": " + message);
}
}
}
クライアント:
package server;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import java.net.URL;
import java.util.Scanner;
import java.util.logging.Level;
import java.util.logging.Logger;
/*
* @author RaKXeR
*/
public class Client {
public static Socket sock;
public static void main(String[] args) {
try {
sock = new Socket("localhost", 3074);
new writeThread().start();
new readThread().start();
} catch (IOException ex) {
Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
}
}
public static class readThread extends Thread {
@Override
public void run() {
boolean loop = true;
while (loop) {
try {
DataInputStream in = new DataInputStream(sock.getInputStream());
//BufferedReader in = new BufferedReader(new InputStreamReader(sock.getInputStream()));
String msg = in.readUTF();
//String msg = in.readLine();
System.out.println(msg);
} catch (IOException ex) {
System.out.println("read error");
Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
loop = false;
}
}
}
}
public static class writeThread extends Thread {
@Override
public void run() {
boolean loop = true;
while(loop) {
try {
DataOutputStream out = new DataOutputStream(sock.getOutputStream());
System.out.println("Type your message to the server: ");
Scanner scan = new Scanner(System.in);
out.writeUTF(scan.nextLine());
} catch (IOException ex) {
System.out.println("write error");
Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
loop = false;
}
}
}
}
}
を
このプログラムはあまり効果がありません。サーバーを開き、サーバーソケット上の着信接続を待っているスレッドを開始します。サーバーソケットに接続しようとするクライアントを開くと、接続を受け入れ、そのスレッド配列リストに新しいスレッドを追加し、そのクライアント/クライアントソケットからのメッセージの待機を開始します。
新しいクライアントが接続しようとするたびに、私は彼を別のスレッドに追加して、すぐに両方のクライアントと対話することができます。
1つのクライアントがサーバーにメッセージを送信するとすぐに、サーバーは接続されているすべてのクライアントに同じメッセージをスレッドの番号と共に送信します。そして、これらのすべてが意図どおりに機能します。
しかし、私の問題は、クライアントの1つを停止するとすべてが機能しなくなることです。私が私にこのxDを求めるとは思わないと知っていたから正確に私が意味することを説明するのではなく、あなた自身でコードをテストするほうがよいでしょう。
実際の質問:これは何が原因で、私のコードに関するすべてを変更することなくこれを修正できますか?私は、サーバソケットをいくつかのクライアントソケットを作成するために再利用していることに気づいていますが、わかりません。
EDIT:あなたは、ジム・ギャリソンの答えの下に見ることができる、と彼は、問題が何であったかを説明 - 私はオフラインたクライアントに他のクライアントのメッセージを送信しようとしていた、それが例外をスローし、停止します糸。私が修正したのは、閉じられたスレッドの名前に "Terminated"の "T"を追加して、スレッドのすべての名前をチェックしてから情報を送信することでした。それは完璧ではありませんが、私は今すぐ解決しています。このスレッドのコードをベースとして使用したことがある場合は、このコードが優れたxDではないため、ごめんなさい。とにかく、元のプログラムのように、改善することをお勧めします。ここでは、固定サーバーコードは次のとおりです。1つのクライアントが終了
package server;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;
public class Server {
public static volatile ArrayList<ReplyThread> connections = new ArrayList<>();
public static void main(String[] args) {
new AcceptThread().start();
}
private static class AcceptThread extends Thread {
@Override
public void run() {
ServerSocket inSock;
try {
inSock = new ServerSocket(3074);
boolean loop = true;
while(loop) {
System.out.println("waiting for next connection");
connections.add(new ReplyThread(inSock.accept()));
System.out.println("connection made");
connections.get(connections.size() - 1).setName(""+(connections.size() - 1));
connections.get(connections.size() - 1).start();
}
inSock.close();
} catch (IOException ex) {
System.out.println(ex.getMessage());
}
}
}
public static class ReplyThread extends Thread {
private static Socket sock;
private DataOutputStream out;
public ReplyThread(Socket newSock) {
sock = newSock;
}
@Override
public void run() {
try {
DataInputStream in = new DataInputStream(sock.getInputStream());
out = new DataOutputStream(sock.getOutputStream());
boolean loop = true;
while(loop) {
String msg = in.readUTF();
System.out.println(msg);
for (ReplyThread thread : connections) {
if (!thread.getName().contains("T")) thread.output(sock, msg);
}
}
in.close();
} catch (SocketException ex) {
//Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
System.out.println("Connection terminated.");
this.setName(this.getName() + "T");
this.interrupt();
System.out.println(this.getName() + " I was interrupted");
} catch (IOException ex) {
Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
}
}
public final void output(Socket sock, String message) throws IOException {
this.out.writeUTF(this.getName() + ": " + message);
}
}
}
クラッシュ後にサーバーログを追加できますか? – pedrofb
どのようにクライアントの実行を停止しますか?_どちらの側でも正常に接続をシャットダウンするコードはありません。 –
ここで大きな同時実行性の問題があります。 'Socket'メンバは静的であるクラスでは静的であってはいけません。 – EJP