2012-05-17 130 views
-4

下面是處理多用戶聊天的客戶端和服務器的代碼。但是當一個客戶端寫入「退出」時,其他當前連接的客戶端也終止,並且我不能連接另一個客戶端。任何人都可以幫忙嗎?Java多線程多客戶端錯誤

這裏是我的客戶端代碼:

class TCPClientsc { 
    public static void main(String argv[]) throws Exception { 
     String modifiedSentence; 
     InetAddress inetAddress = InetAddress.getLocalHost(); 
     System.out.println(inetAddress); 

     Socket clientSocket = new Socket(inetAddress, 6789); 
     DataOutputStream outToServer = new DataOutputStream(clientSocket.getOutputStream()); 

     BufferedReader inFromServer = new BufferedReader(new InputStreamReader(clientSocket.getInputStream())); 

     CThread write = new CThread(inFromServer, outToServer, 0, clientSocket); 
     CThread read = new CThread(inFromServer, outToServer, 1, clientSocket); 
    } 
} 

class CThread extends Thread { 
    BufferedReader inFromServer; 
    DataOutputStream outToServer; 
    Socket clientSocket = null; 
    int RW_Flag; 
    public CThread(BufferedReader in, DataOutputStream out, int rwFlag, Socket clSocket) { 
     inFromServer = in; 
     outToServer = out; 
     RW_Flag = rwFlag; 
     clientSocket = clSocket; 
     start(); 
    } 
    public void run() { 
     String sentence; 
     try { 
      while (true) { 
       if (RW_Flag == 0) {// write 
        BufferedReader inFromUser = new BufferedReader(new InputStreamReader(System.in)); 
        sentence = inFromUser.readLine(); 

        // System.out.println("Writing "); 
        outToServer.writeBytes(sentence + '\n'); 
        if (sentence.equals("quit")) 
         break; 

       } else if (RW_Flag == 1) { 
        sentence = inFromServer.readLine(); 
        if (sentence.endsWith("quit")) 
         break; 
        System.out.println("(received)" + sentence); 
       } 
      } 
     } catch (Exception e) { 
     } finally { 
      try { 
       inFromServer.close(); 
       outToServer.close(); 
       clientSocket.close(); 

      } catch (IOException ex) { 
       Logger.getLogger(CThread.class.getName()).log(Level.SEVERE, null, ex); 
      } 
     } 
    } 
} 

Server代碼:

class TCPServersc { 
    static int i = 0; 
    static SThread tt[] = new SThread[100]; 
    static SThread anot[] = new SThread[100]; 
    public static void main(String argv[]) throws Exception { 
     String client; 
     String capitalizedSentence; 
     ServerSocket welcomeSocket = new ServerSocket(6789); 

     while (true) { 
      Socket connectionSocket = welcomeSocket.accept(); 
      i++; 
      System.out.println("connection :" + i); 
      BufferedReader inFromClient = new BufferedReader(newInputStreamReader(connectionSocket.getInputStream())); 
      DataOutputStream outToClient = new DataOutputStream(connectionSocket.getOutputStream()); 
      BufferedReader inFromMe = new BufferedReader(new InputStreamReader(System.in)); 

      tt[i] = new SThread(inFromClient, outToClient, tt, 0, connectionSocket, i); 
      anot[i] = new SThread(inFromMe, outToClient, tt, 1, connectionSocket, i); 
     } 
    } 
} 

// =========================================================== 
class SThread extends Thread { 
    BufferedReader inFromClient; 
    DataOutputStream outToClient; 
    String clientSentence; 
    SThread t[]; 
    String client; 
    int status; 
    Socket connectionSocket; 
    int number; 

    public SThread(BufferedReader in, DataOutputStream out, SThread[] t, int status, Socket cn, int number) { 
     inFromClient = in; 
     outToClient = out; 
     this.t = t; 
     this.status = status; 
     connectionSocket = cn; 
     this.number = number; 
     start(); 
    } 

    public void run() { 
     try { 
      if (status == 0) { 
       clientSentence = inFromClient.readLine(); 
       StringTokenizer sentence = new StringTokenizer(clientSentence, " "); 

       // /////////////////////////////////////////////////////////// 
       if (sentence.nextToken().equals("login")) { 
        String user = sentence.nextToken(); 
        String pass = sentence.nextToken(); 
        FileReader fr = new FileReader("file.txt"); 
        BufferedReader br = new BufferedReader(fr); 
        int flag = 0; 
        while ((client = br.readLine()) != null) { 
         if ((user.equals(client.substring(0, 5))) && (pass.equals(client.substring(6, 10)))) { 
          flag = 1; 
          System.out.println(user + " has logged on"); 
          for (int j = 1; j <= 20; j++) { 
           if (t[j] != null) 
            t[j].outToClient.writeBytes(user + " has logged on" + '\n');// '\n' is necessary 
          } 
          break; 
         } 
        } 
        if (flag == 1) { 
         while (true) { 
          clientSentence = inFromClient.readLine(); 
          System.out.println(user + " : " + clientSentence); 
          for (int j = 1; j <= 20; j++) { 
           if (t[j] != null) 
            // '\n' is necessary 
            t[j].outToClient.writeBytes(user + " : " + clientSentence + '\n'); 
          } 
          // if(clientSentence.equals("quit"))break; 
         } 
        } 
       } 
      } 
      // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////// 
      if (status == 1) { 
       while (true) { 
        clientSentence = inFromClient.readLine(); 
        if (clientSentence.equals("quit")) 
         break; 

        System.out.println("Server: " + clientSentence); 
        for (int j = 1; j <= 20; j++) { 
         if (t[j] != null) 
          t[j].outToClient.writeBytes("Server :" + clientSentence + '\n');// '\n' is necessary 
        } 
       } 
      } 
     } catch (Exception e) { 
     } finally { 
      try { 
       // System.out.println(this.t); 
       inFromClient.close(); 
       outToClient.close(); 
       connectionSocket.close(); 
      } catch (IOException ex) { 
       Logger.getLogger(SThread.class.getName()).log(Level.SEVERE, null, ex); 
      } 
     } 
    } 
} 
+0

推測問題出在服務器上,而不是客戶端上,因爲一個客戶端可能會影響到另一個客戶端。我們必須看到服務器代碼。 –

+4

請格式化您的代碼並刪除註釋掉的語句。如果你問別人花時間讀你的代碼,你應該願意讓它可讀。 –

+0

我們不傾向於通過你的豐富和格式不正確的代碼。減少並格式化,然後你*有機會 – Bohemian

回答

1

此代碼有很多問題。

  • 首先,在未來,請張貼是很好的格式化,簡潔的代碼片段。我只是基本上重新格式化您的文章中的所有內容。
  • 我看到幾個地方你正在捕捉異常,但什麼都不做。這是巨大的不好的做法。至少你應該打印/記錄你捕捉到的異常。我懷疑這是造成你的問題。
  • 我覺得RW_Flag很混亂。那麼你應該有兩個客戶端線程。一個從System.in寫入服務器,另一個讀取。沒有一個客戶端線程做2件事。與服務器中的status標誌相同。這應該是2個不同的線程。
  • 而不是服務器中的int flag = 0;,應該是boolean loggedIn;。在Java中使用布爾值代替C風格的標誌並使用更好的變量名稱。代碼可讀性將爲自己付出代價。 statusRW_flag等。
  • 代替巨大的代碼塊,您應該將連續代碼移出方法:handleSystemIn(),handleClient(),talkToServer()。一旦你在你的代碼中創建了更多的方法,並縮減了各個代碼塊,它就使得它更具可讀性/可調試性/可理解性。
  • 您需要在該數組的每個用法周圍有一個synchronized (tt)塊。一旦有多個線程全部使用tt如果主線程accept添加到線程中,則需要同步更新。

我沒有立即看到這個問題雖然通心粉代碼是太難以解析。我懷疑你在某處拋出和異常,這是客戶在第一個客戶退出後無法連接的原因。除此之外,我會繼續使用System.out.println自由使用調試來查看哪些消息正在發送到哪裏。