在我的聊天客户机/服务器程序中,我在向所有连接的客户端广播消息时遇到了困难。发送的消息似乎只被发送回原始服务器,即使我正在迭代一个ArrayList。我有一个套接字的ArrayList和一个将读消息作为参数并为每个套接字创建一个PrintWriter的方法。我认为这个问题与我的客户类有关(如果我错了,请原谅),但我还没有搞清楚是什么。
客户类:
public class H7Client extends Thread implements ActionListener{
private JTextField jtfPortName = new JTextField(20);
private JTextField jtfHostName = new JTextField(20);
private String hostName;
private int portNumber;
private JTextArea jtaChat = new JTextArea("Send a message to the client", 15,40);
private JTextArea jtaRecive = new JTextArea("WELCOME TO THE CHAT!", 15,40);
private JTextField jtfUName = new JTextField("user");
public H7Client(){
    JFrame defaultFrame = new JFrame();
    JLabel jlPortName = new JLabel("Enter The Port number");
    JLabel jlHostName = new JLabel("Enter the Host name");
    JLabel jlUName = new JLabel("Enter a username");
    JButton jbSetSocketInfo = new JButton("Confirm Port and Host Info");
    JButton jbExit = new JButton("Exit");
    JButton jbSendText = new JButton("Send");
    jbSetSocketInfo.addActionListener(this);
    jbExit.addActionListener(this);
    jbSendText.addActionListener(this);
    JPanel jpNorth = new JPanel();
    JPanel jpCenter = new JPanel();
    JPanel jpLabels = new JPanel();
    defaultFrame.add(jpNorth,BorderLayout.NORTH);
    jpNorth.add(jbSetSocketInfo,BorderLayout.EAST);
    jpNorth.add(jbSendText, BorderLayout.CENTER);
    jpNorth.add(jbExit,BorderLayout.WEST);
    defaultFrame.add(jpCenter,BorderLayout.CENTER);
    jpCenter.add(jtaChat,BorderLayout.SOUTH);
    jpCenter.add(jpLabels,BorderLayout.NORTH);
    jpLabels.setLayout(new GridLayout(2,3));
    jpLabels.add(jlHostName);
    jpLabels.add(jlPortName);
    jpLabels.add(jlUName);
    jpLabels.add(jtfHostName);
    jpLabels.add(jtfPortName);
    jpLabels.add(jtfUName);
    defaultFrame.add(jtaRecive,BorderLayout.SOUTH);
    defaultFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    defaultFrame.setLocationRelativeTo(null);
    defaultFrame.setSize(800,800);
    defaultFrame.setVisible(true);
}
public void setClientComms(String message){
    try{
        // open communications to the server
        Socket s = new Socket(hostName, portNumber);
        ClientThread ct = new ClientThread(s, message);
    }
    catch(IOException e){
        e.printStackTrace();
    }
}
class ClientThread extends Thread{
    public ClientThread(Socket sock, String msg) {
        try {
            // open input stream
            InputStream in = sock.getInputStream();
            BufferedReader br = new BufferedReader(
                    new InputStreamReader(in));
            // open output stream
            OutputStream out = sock.getOutputStream();
            PrintWriter pout = new PrintWriter(
                    new OutputStreamWriter(out));
            // write something to the server
            pout.println(msg);
            // make sure it went
            pout.flush();
            // read something back from server
            String incomingMessage = br.readLine();
            // print the something to the user
            System.out.println("Message: " + msg);
            //jtaChat.setText("");
            jtaRecive.append("\n" + msg);
            // Send the terminating string to the server
            pout.println("quit");
            pout.flush();
            // close everything
            pout.close();
            br.close();
            sock.close();
        } catch (UnknownHostException uhe) {
            System.out.println("What host you speak of?");
        } catch (IOException ioe) {
            System.out.println("Bad IO?");
            ioe.printStackTrace();
        }
    }
}
public void actionPerformed(ActionEvent event) {
    if (event.getActionCommand().equals("Exit")) {
        System.exit(0);
    } else if (event.getActionCommand().equals("Send")) {
        String chatMessage = jtaChat.getText();
        jtaChat.setText("");
        setClientComms(chatMessage);
    } else if (event.getActionCommand().equals("Confirm Port and Host Info")) {
        hostName = jtfHostName.getText();
        //NEED TO ADD IN WAY TO HANDLE IP ADDRESSES
        portNumber = Integer.parseInt(jtfPortName.getText());
    }
}
public static void main(String [] args) {
    new H7Client();
}}
服务器类:
public class H7Server{
public ArrayList<Socket> clients = new ArrayList<Socket>();
public static void main(String[] args){new H7Server();}
public H7Server()
{
    ServerSocket ss = null;
    try {
        System.out.println("getLocalHost: "+ InetAddress.getLocalHost() );
        System.out.println("getByName:    "+InetAddress.getByName("localhost") );
        ss = new ServerSocket(16789);
        Socket cs = null;
        while(true){        // run forever once up
            //try{
            cs = ss.accept();               // wait for connection
            clients.add(cs);
            ThreadServer ths = new ThreadServer( cs );
            ths.start();
       } // end while
    }
    catch( BindException be ) {
        System.out.println("Server already running on this computer, stopping.");
    }
    catch( IOException ioe ) {
        System.out.println("IO Error");
        ioe.printStackTrace();
    }
} // end main
class ThreadServer extends Thread {
    Socket cs;
    public ThreadServer( Socket cs ) {
        this.cs = cs;
    }
    public void run() {
           BufferedReader br;
           String clientMsg;
           try {
               br = new BufferedReader(
                       new InputStreamReader(
                               cs.getInputStream()));
               clientMsg = br.readLine();                // from client
               System.out.println("Server read: " + clientMsg);
               while(clientMsg != null) {
                   sendMessage(clientMsg);
               }
           } catch (IOException e) {
               System.out.println("Inside catch");
               e.printStackTrace();
           }
    }
    public synchronized void sendMessage(String s){
        try{
            for(Socket sock: clients) {
                PrintWriter pw = new PrintWriter(new OutputStreamWriter(sock.getOutputStream()));
                pw.println(s);
                pw.flush();
            }
        }
        catch(IOException e){
            e.printStackTrace();
        }
    }
} // end class ThreadServer}
发布于 2017-04-11 06:03:25
正如您所怀疑的,客户机类和服务器类都存在问题。有两件事你需要解决。
首先,您从服务器接收消息,但没有对它做任何操作。客户端在ClientThread构造函数的try块中接收到ClientThread,但未使用。一个可能的修复方法是将其附加到jtaReceive中,并删除另一个附加部分,但不要这样做。
为了进行实时聊天,客户端必须至少有两个线程:一个用于发送消息,另一个用于不断检查是否有任何消息要接收。也许,这正是您试图通过ClientThread实现的,但不幸的是,它并不起作用。除了错误的代码之外,使用ClientThread还会创建一个Thread,但不会实际运行它。您需要在run方法中有一个线程,该线程包含一个永久的while循环,该循环不断地接收来自服务器的消息。一个实现是这样的:(您可以重命名为任何您喜欢的)
class ReceiverThread extends Thread {
    private BufferedReader s;
    public ReceiverThread(Socket sock) throws IOException {
        s = new BufferedReader(new InputStreamReader(sock.getInputStream()));
    }
    @Override
    public void run() {
        while (true) 
            try {
                String message = s.readLine();
                // ...code to do whatever with message...
            } catch (IOException e) {
                e.printStackTrace();
            }
    }
}此外,您还需要创建一个保持打开状态的套接字(在确认主机和端口信息时,可以使用套接字创建并启动这个线程)。
服务器类的问题是我们所有人都要面对的问题:臭名昭著的ConcurrentModificationException。您可以阅读有关它的这里,但基本上这个异常是在修改(添加、删除等)时抛出的。当你不应该这样做的时候,数据结构。所讨论的数据结构是ArrayList of Socket's,以及在发送消息时for-each循环中的时间。基本上,在运行该循环时,创建while‘s的while循环将它们添加到ArrayList中并抛出异常。要解决这个问题,您需要在处于ArrayList循环中时停止修改for,可能是通过移除while循环、在for循环完成之前保持while循环,或者甚至在for循环处于活动状态时添加一个由套接字组成的Queue,但是有很多方法可以做到这一点。
我假设您的服务器只接收一条消息,只是为了测试,但是如果您决定能够聊天多条消息,则必须使用用于客户端类的额外线程。
祝你好运:)
注意:我建议不要使用AWT thread (调用actionPerformed的线程)来建立网络/任何可能需要时间的东西,否则应用程序GUI实际上就会冻结。
https://stackoverflow.com/questions/43336575
复制相似问题