0

したがって、基本的に、キャッチが例外をキャッチしているtry/catchがあります。目的は、クライアントがサーバーに通知せずに切断した場合に、接続されているクライアントのリストからクライアントを削除することです。なぜか釣れないのに。奇妙な部分は、catch にブレークポイントを追加すると (私は eclipse を使用しています)、ブレークポイントが壊れ、続行すると、catch し、サーバーを再起動するまで適切に catch し続けることです。この時点でクライアントが行うことは、サーバーに接続して終了することだけです。サーバー ウィンドウを閉じようとすると、サーバーはこれをキャッチせず、応答を停止します。キャッチしない場合に停止する唯一の方法は、終了することです。

したがって、私のコードが機能することを明確にするために、私の問題はキャッチがキャッチされないことだけであり、その結果、サーバーはクライアントがサーバーを離れたことを認識しません。ブレークポイントを追加すると、何らかの理由で修正されますが、これは私の問題です。

サーバーのほとんどのコードは次のとおりです。

35 public static ArrayList<Socket> list_sockets = new ArrayList<Socket>();
36 public static ArrayList<Integer> list_client_states = new ArrayList<Integer>();
37 public static ArrayList<DataPackage> list_data = new ArrayList<DataPackage>();
38
39 private static Runnable accept = new Runnable() {
40  @Override
41  public void run() {
42      new Thread(send).start();
43      new Thread(receive).start();
44      
45      while (true) {
46          try {
47              Socket socket = server.accept();
48              
49              ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
50              
51              String username = (String) ois.readObject();
52              
53              ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
54              oos.writeObject("Welcome...");
55              
56              list_clients_model.addElement(username + " - " + socket.getInetAddress().getHostAddress() + " - " + socket.getInetAddress().getHostName());
57              list_client_states.add(0);
58              
59              list_data.add(new DataPackage());
60              list_sockets.add(socket);
61          }
62          catch (Exception e) {}  
63      }   
64  }
65 };
66
67 private static Runnable send = new Runnable() {
68  @Override
69  public void run() {
70      ObjectOutputStream oos;
71      
72      while (true) {
73          for (int i = 0; i < list_sockets.size(); i++){
74              try {
75                  oos = new ObjectOutputStream(list_sockets.get(i).getOutputStream());
76                  int client_state = list_client_states.get(i);
77                  oos.writeObject(client_state);
78                  
79                  oos = new ObjectOutputStream(list_sockets.get(i).getOutputStream());
80                  oos.writeObject(list_data);
81                  
82                  if (client_state == 1) { // Kicked by server
83                      disconnectClient(i);
84                      i--;
85                  }
86                  else if (client_state == 2) { // Server Disconnected
87                      disconnectClient(i);
88                      i--;
89                  }
90              }
91              catch (Exception e) {}
92          }
93      }
94  }
95 };
96
97 private static Runnable receive = new Runnable() {
98  @Override
99  public void run() {
100     ObjectInputStream ois;
101     
102     while (true) {
103        //System.out.println(list_sockets.size());
104        for (int i = 0; i < list_sockets.size(); i++) {
105             try {
106                 ois = new ObjectInputStream(list_sockets.get(i).getInputStream());
107                 int receive_state = (Integer) ois.readObject();
108                 
109                 ois = new ObjectInputStream(list_sockets.get(i).getInputStream());
110                 DataPackage dp = (DataPackage) ois.readObject();
111                 
112                 list_data.set(i, dp);
113                 
114                 if (receive_state == 1) { // Client disconnected by user
115                     disconnectClient(i);
116                     i--;
117                 }
118             }
119             catch (Exception e) { // Client Disconnected (Client didn't notify server about disconnecting)
120                 disconnectClient(i);
121                 i--;
122                 e.printStackTrace();
123                 
124             }
125         }
126     }
127 }
128 };

そして、サーバーの切断方法:

public static void disconnectClient(int index) {
    try {
        list_clients_model.removeElementAt(index);
        list_client_states.remove(index);
        list_data.remove(index);
        list_sockets.remove(index);
    }
    catch (Exception e) {}
}

ブレークポイントを追加したときに発生する例外は次のとおりです (追加しないと発生しません)。

java.net.SocketException: Connection reset
at java.net.SocketInputStream.read(Unknown Source)
at java.net.SocketInputStream.read(Unknown Source)
at java.io.ObjectInputStream$PeekInputStream.read(Unknown Source)
at java.io.ObjectInputStream$PeekInputStream.readFully(Unknown Source)
at java.io.ObjectInputStream$BlockDataInputStream.readShort(Unknown Source)
at java.io.ObjectInputStream.readStreamHeader(Unknown Source)
at java.io.ObjectInputStream.<init>(Unknown Source)
at ServerMain$3.run(ServerMain.java:105)
at java.lang.Thread.run(Unknown Source)

したがって、更新として、103行目のコメントを外しても機能します。また、コメントで、チュートリアルに従っていることを言及しました。 ?v=VFF0JRCFCH0

編集: azzurroverde に感謝します。実際、問題は私のリストが同期されていないことでした。行 35 ~ 37 を次のように変更すると、問題が修正され、正常に動作するようになりました。

35 public static List<Socket> list_sockets = Collections.synchronizedList(new ArrayList<Socket>());
36 public static List<Integer> list_client_states = Collections.synchronizedList(new ArrayList<Integer>());
37 public static List<DataPackage> list_data = Collections.synchronizedList(new ArrayList<DataPackage>());
4

1 に答える 1

0

この長い議論の後、答えを要約しましょう:)問題は、ArrayListが同期されておらず、異なるスレッドが同時にアクセスしていて、不安定な状態のままだったことです。

public static ArrayList<Socket> list_sockets = new ArrayList<Socket>();

解決策は、配列リストを同期することでした: http://docs.oracle.com/javase/7/docs/api/java/util/ArrayList.html

List list = Collections.synchronizedList(new ArrayList(...));
于 2013-09-05T21:37:50.760 に答える