我遇到了麻烦,我有服务器 - 客户端连接工作,任何数量的客户端都可以连接聊天并相互发送消息。但如果有人通过单击右上角的X退出GUI,一切都会进入****,未来的加入客户端无法做任何事情。
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 :(得分:0)
首先,通过对try子句的放置位置进行一些简单的更改,防止服务器崩溃。
在服务器中执行以下操作:
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()
注意如何移动try以围绕仅发送的消息(而不是for循环),这样如果一条消息无法发送,那么它将跳过它并在for循环中发送下一条消息而不是崩溃。
现在对你的protected void sendArrayList(){
方法做同样的事情,移动try / catch只包围这两行,而不是围绕for循环:
out2.writeObject(clientNames);
out2.reset();
还应进行以下更改,以便您不向最近断开连接的客户端发送消息:
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