2017-05-07 9 views
0

서버 - 클라이언트 연결이 작동하고 클라이언트 수가 많아서 채팅에 연결하고 서로 메시지를 보낼 때 문제가 있습니다. 그러나 누군가가 오른쪽 상단의 X를 클릭하여 GUI를 종료하면 모든 것이 ****이되어 향후 참여하는 클라이언트는 아무 것도 할 수 없습니다. GUI에서 X를 누를 때 이후 클라이언트에서 Java 채팅이 작동을 멈 춥니 다.

import javax.swing.*; 
import java.awt.*; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import java.io.IOException; 
import java.io.ObjectInputStream; 
import java.io.ObjectOutputStream; 
import java.net.Socket; 
import java.net.UnknownHostException; 
import java.util.ArrayList; 

public class ChatC extends JFrame { 

//Attributes 
private JTextArea msgArea = new JTextArea(); 
private JTextField input = new JTextField(45); 
private JTextArea onlineUsers; 
private ArrayList<String> clientNames; 
private String clientName = null; 
private ObjectOutputStream out; 
private Socket client; 

/** 
* ChatC constructor 
* Creates an interactive GUI for the user 
* Establishes connection with the server 
*/ 
public ChatC() { 

    clientName = JOptionPane.showInputDialog("Enter username:"); 
    if (clientName == null || clientName.equals("")) clientName = "Guest" + 
    (int) (Math.random() * 200); 

    setSize(600, 600); 
    setLocationRelativeTo(null); 
    setTitle("Welcome to Connect Four chat room, " + clientName); 
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
    setResizable(false); 
    setLayout(new BorderLayout()); 

    JButton sendMsg = new JButton("ENTER"); 
    getRootPane().setDefaultButton(sendMsg); 

    msgArea.setEditable(false); 

    JPanel south = new JPanel(new BorderLayout()); 

    JScrollPane scrollPane = new JScrollPane(msgArea); 
    add(scrollPane, BorderLayout.CENTER); 

    onlineUsers = new JTextArea(); 
    onlineUsers.setEditable(false); 
    add(onlineUsers, BorderLayout.EAST); 
    south.add(input, BorderLayout.WEST); 
    south.add(sendMsg, BorderLayout.EAST); 
    add(south, BorderLayout.SOUTH); 

    JMenu menu = new JMenu("Menu"); 
    JMenuItem exit = new JMenuItem("Logout"); 
    menu.add(exit); 
    JMenuBar menuBar = new JMenuBar(); 
    menuBar.add(menu); 
    setJMenuBar(menuBar); 

    exit.addActionListener(new ActionListener() { 

     public void actionPerformed(ActionEvent ae){ 

      JOptionPane.showMessageDialog(null, "Thanks for playing Connect Four!", "Farewell", JOptionPane.INFORMATION_MESSAGE); 

      try{ 

       out.writeObject("////" + clientName); 
       out.flush(); 

      } 
      catch (IOException e1) {} 

     }//end of actionPerformed() 

    });//end of anonymous ActionListener 

    setVisible(true); 

    try{ 

     client = new Socket("localhost", 16789); 
     out = new ObjectOutputStream(client.getOutputStream()); 
     out.writeObject(clientName); 

     sendMsg.addActionListener(new ActionListener(){ 

      public void actionPerformed(ActionEvent ae){ 

       if (input.getText() != null && !input.getText().equals("")) { 
        try{ 

         out.writeObject(input.getText()); 
         out.flush(); 

        }//end of try 
        catch (IOException ioe){} 

        input.setText(null); 

       }//end of if 

      }//end of actionPerformed() 

     });//end of anonymous ActionListener 

    }//end of try 
    catch (UnknownHostException uhe){} 
    catch (IOException ioe) {} 

    ChatCInner chatInner = new ChatCInner(client); 
    chatInner.start(); 

}//end of ChatC() 

/** 
* Main method 
* @param args Project arguments array 
*/ 
public static void main(String[] args) { 
    new ChatC(); 
} 

/** 
* Method that displays names of users that are currently participating in the chat room 
*/ 
protected void setOnlineUsers(){ 

    onlineUsers.setText("Users Online: \n"); 

    for (Object o : clientNames) { 

     onlineUsers.append(o + "\n"); 

    }//end of for each 

}//end of setOnlineUsers() 

/** 
* Inner class that functions as a thread for each client 
* Handles user's actions on the GUI and communication with the server 
*/ 
private class ChatCInner extends Thread { 

    //Attributes 
    Object obj; 
    ObjectInputStream in; 
    Socket clientC; 

    /** 
    * ChatCInner constructor 
    * @param cl Client socket 
    */ 
    public ChatCInner(Socket cl){ 

     clientC = cl; 

    }//end of ChatCInner() 

    /** 
    * Method that defines what each thread does 
    * Handles client interaction(sending messages etc.) 
    */ 
    public void run() { 

     try{ 

      in = new ObjectInputStream(clientC.getInputStream()); 

      while ((obj = in.readObject()) != null) { 

       if (obj instanceof String) { 

        msgArea.append((String) obj); 
        msgArea.setCaretPosition(msgArea.getDocument().getLength()); 

       }//end of if 

       if (obj instanceof ArrayList) { 

        clientNames = (ArrayList<String>) obj; 

        if ((clientNames.indexOf(clientName) == -1)) { 

         client.close(); 
         System.exit(1); 

        }//end of if 
        else setOnlineUsers(); 

       }//end of if 

      }//end of while loop 

     }//end of try 
     catch (NullPointerException npe) {} 
     catch (IOException ioe) { 

      JOptionPane.showMessageDialog(null, "Server was shut down... leaving chat room.", "Server malfunctioning",JOptionPane.WARNING_MESSAGE); 
      System.exit(1); 

     } 
     catch (ClassNotFoundException cnfe) {} 

    }//end of run() 

}//end of ChatInner class 

}//end of ChatC class 

클라이언트

import javax.swing.*; 
import java.awt.*; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import java.io.IOException; 
import java.io.ObjectInputStream; 
import java.io.ObjectOutputStream; 
import java.net.*; 
import java.util.ArrayList; 
import java.util.Vector; 

public class ChatS extends JFrame { 

//Attributes 
private ArrayList<String> clientNames = new ArrayList<>(); 
private Vector<ObjectOutputStream> outList = new Vector<>(); 
private Socket client = null; 

/** 
* ChatS constructor 
* Build simple GUI with a button to terminate server 
* Establishes connection with clients 
*/ 
public ChatS() { 

    setTitle("Server Operational"); 
    setSize(300, 150); 
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
    setLocationRelativeTo(null); 
    setLayout(new GridLayout(0, 1)); 

    JButton stopServer = new JButton("Terminate Server"); 

    try{ 

     ServerSocket server = new ServerSocket(16789); 

     JLabel localhost = new JLabel(InetAddress.getLocalHost().toString()); 
     JLabel hostName = new JLabel(InetAddress.getByName("localhost").toString()); 
     add(localhost); 
     add(hostName); 

     stopServer.addActionListener(new ActionListener() { 

      @Override 
      public void actionPerformed(ActionEvent e) { 

       System.exit(0); 

      }//end of actionPerformed() 

     }); 

     add(stopServer); 
     setVisible(true); 

     while (true) { 

      client = server.accept(); 
      ChatSInner st = new ChatSInner(client); 
      st.start(); 

     }//end of while loop 

    }//end of try 
    catch(IOException ioe){} 

}//end of ChatS() 

/** 
* Main method 
* @param args Project arguments array 
*/ 
public static void main(String[] args){ new ChatS(); } 

/** 
* Inner class that functions as a thread 
* Handles user interaction on the chat 
*/ 
public class ChatSInner extends Thread { 

    //Attributes 
    private int index; 
    private ObjectInputStream in; 
    private ObjectOutputStream out; 
    private Socket clientInner; 

    /** 
    * ChatSInner constructor 
    * Handles clients as separate threads 
    * @param cl Socket of the client 
    */ 
    public ChatSInner(Socket cl){ 

     try { 

      clientInner = cl; 
      in = new ObjectInputStream(clientInner.getInputStream()); 
      out = new ObjectOutputStream(clientInner.getOutputStream()); 
      outList.add(out); 

     }//end of try 
     catch(IOException ioe){} 

    }//end of ChatSInner() 

    /** 
    * Method to broadcasts message to all clients connected to chat 
    * @param msg Message that a client is sharing with everyone 
    */ 
    protected void sendMsg(String msg){ 

     try { 

      for (ObjectOutputStream out2 : outList){ 

       out2.writeObject(msg + "\n"); 
       out2.reset(); 

      }//end of for each 

     }//end of try 
     catch(IOException ioe){} 

    }//end of sendMsg() 

    /** 
    * Method that sends ArrayList of online users back to each client 
    */ 
    protected void sendArrayList(){ 

     try{ 

      for (ObjectOutputStream out2 : outList) { 

       out2.writeObject(clientNames); 
       out2.reset(); 

      }//end of for each 

     }//end of try 
     catch(IOException ioe){} 

    }//end of sendArrayList() 

    /** 
    * Method that defines what each thread does 
    * Handles client interaction in the chat room (sending messages etc.) 
    */ 
    public void run() { 

     String clientName; 

     try{ 

      Object obj; 
      clientName = (String) in.readObject(); 
      clientNames.add(clientName); 
      index = clientNames.indexOf(clientName); 

      sendMsg(clientName + " has entered the chat room.\n"); 
      sendArrayList(); 

      while ((obj = in.readObject()) != null){ 

       if (obj instanceof String) { 

        if ((((String) obj).length() > 4) && ((String) obj).substring(0, 4).equals("////")){ 

         sendMsg(clientNames.get(index) + " has logged out of the chat room.\n"); 
         clientNames.remove(clientName); 
         sendArrayList(); 

        } //end of if 
        else sendMsg(clientName + ": " + obj); 

       }//end of if 

      }//end of while loop 

     } //end of try 
     catch(IOException ioe){} 
     catch(ClassNotFoundException cnfe) {} 

    }//end of run() 

}//end of ChatSInner class 

}//end of ChatS class 

이 서버

답변

0

먼저 당신이 당신의 시도는 조항을 넣어 곳으로 몇 가지 간단한 변경하여 충돌에서 서버를 방지 할 수 있습니다입니다. 이것 대신에

protected void sendMsg(String msg){ 
    for (ObjectOutputStream out2 : outList){ 
     try {//try moved to this line 
      out2.writeObject(msg + "\n"); 
     }//end of try 
     out2.reset();//reset even if an error occurs so that the next message sends smoothly 
    catch(IOException ioe){} //catch moved to this line 
    }//end of for each 
}//end of sendMsg() 

: 서버에서

은 이렇게하려면 시도가 (루프가 아닌) 만 보내는 메시지를 둘러싸고 이동 한 방법

protected void sendMsg(String msg){ 
    try { 
     for (ObjectOutputStream out2 : outList){ 
      out2.writeObject(msg + "\n"); 
      out2.reset(); 
     }//end of for each 
    }//end of try 
    catch(IOException ioe){} 
}//end of sendMsg() 

주, 수 있도록 한 메시지가 전송에 실패하면 메시지를 건너 뛰고 충돌 대신 for 루프에서 다음 메시지를 보냅니다. 당신이 '돈 있도록

out2.writeObject(clientNames); 
out2.reset(); 

다음과 같이 변경도해야한다 :

지금이 두 줄을 포위하기 위해 시도/캐치를 이동 만이 아닌 루프에 대한 주변, 당신의 protected void sendArrayList(){ 방법으로 동일한 작업을 수행 t는 최근 연결 클라이언트에 메시지를 보내

   if ((((String) obj).length() > 4) && ((String) obj).substring(0, 4).equals("////")){ 

        //first copy the users name so we can use it in our message: 
        String disconnectedUser = clientNames.get(index); 
        //now remove the disconnected user before you do anything else: 
        clientNames.remove(clientName); 
        //now you can send your message without causing the error because the disconnected client has been removed from the clientName list: 
        sendMsg(clientNames.get(index) + " has logged out of the chat room.\n"); 

        sendArrayList(); 

       } //end of if 
+0

나는 또한 클라이언트가 연결되어있는 경우 클라이언트가 항상 가까운 메시지'out.writeObject를 보낼 수 없기 때문에 당신이 확인하는 방법을 다시 생각 제안 ("////"+ clientName);', 특히 클라이언트가 강제 종료 된 경우 또는 i f 네트워크 연결이 끊어졌습니다. – sorifiend

+0

감사합니다. 도움이되었습니다. :) 기본 닫기 작업 대신 창 닫기를위한 창 수신기를 설정했습니다. –