Java Sockets 和 ServerSockets 服务器/客户端 GUI 聊天程序

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/20296628/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 00:55:13  来源:igfitidea点击:

Sockets and ServerSockets Server/Client GUI Chat Program

javamultithreadingswingsocketsserversocket

提问by Ashton

I'm trying to learn how sockets and ServerSockets work in Java so I tried to do a Chat Server but at the same time using threading to handle each client. I think I need some fresh eyes on my code because I have no idea why it's not working. The program starts but the client does not connect and the is not created. I'm fairly certain something is wrong in my client class but I'm not certain what needs to be fixed. Any help at all, even just a link to a helpful resource, would be very appreciated. Thanks.

我试图了解套接字和 ServerSockets 在 Java 中是如何工作的,所以我尝试做一个聊天服务器,但同时使用线程来处理每个客户端。我想我需要重新审视我的代码,因为我不知道为什么它不起作用。程序启动但客户端未连接且未创建。我相当确定我的客户课程有问题,但我不确定需要修复什么。任何帮助,甚至只是一个有用资源的链接,都将不胜感激。谢谢。

Server Code

服务器代码

     package chatbox.server;

        import static java.lang.System.out;

        import java.io.IOException;
        import java.io.InputStream;
        import java.io.InputStreamReader;
        import java.io.OutputStream;
        import java.io.PrintStream;
        import java.net.ServerSocket;
        import java.net.Socket;
        import java.util.ArrayList;
        import java.util.Scanner;


     public class Server {


    public final static int DEFAULT_PORT = 5000;

    private ServerSocket socket;
    private ArrayList<Socket> clients;


    public Server(int port) throws IOException {
        System.out.println("Server is now online");
        System.out.println("port: " + port);
        this.socket = new ServerSocket(port);
        System.out.println("Listening socket established");
        System.out.println("Waiting for connections...");
        this.clients = new ArrayList<Socket>();


        while (true) {
            try {
                final Socket connection = this.socket.accept();
                this.clients.add(connection);


                Runnable incomingMsg = new Runnable() {
                    private InputStream inputStream = connection.getInputStream();
                    private InputStreamReader reader = new InputStreamReader(
                            inputStream);
                    private Scanner scanner = new Scanner(reader);

                    @Override
                    public void run() {
                        while (true) {
                            if (scanner.hasNextLine()) {
                                String msg = scanner.nextLine();
                                System.out.println("Handling message: \"" + msg
                                        + "\"");
                                notifyAllConnections(msg);
                            }
                        }
                    }

                };

                Thread thread = new Thread(incomingMsg);


                thread.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {

                    @Override
                    public void uncaughtException(Thread thread, Throwable exc) {
                        try {
                            connection.close();
                        } catch (IOException e1) {

                            e1.printStackTrace();
                        } finally {
                            clients.remove(connection);
                            System.out.println("Removed connection");
                        }

                    }
                });
                thread.start();
                System.out.println("Added new connection");
            } catch (IOException exc) {

                System.out
                        .println("Error occurred.");
            }
        }
    }

    protected void notifyAllConnections(String msg) {
        for (Socket sock : this.clents) {
            try {
                OutputStream out = sock.getOutputStream();
                PrintStream printer = new PrintStream(out);
                printer.println(msg);
                printer.flush();
            } catch (IOException exc) {
                System.out.println("Message was not fully broadcast");
            }

        }
    }

    public static void main(String[] args) {
        try {
            Server server = new Server(
                    Server.DEFAULT_PORT);
        } catch (IOException exc) {
            System.out
                    .println("Could not create the server socket.");
            exc.printStackTrace();
            String servername = "localhost";
            try {
                new Client(servername, 5000);
            } catch (Exception ex) {
                out.println("Error" + ex.getMessage());

            }
        }
    }
    }

Client Code

客户代码

     package chatbox.client

        import java.awt.event.ActionListener;

        import javax.swing.JFrame;
        import java.io.*;
        import java.util.*;
        import java.net.*;
        import javax.swing.*;
        import java.awt.*;
        import java.awt.event.*;
        import static java.lang.System.out;

        public class Client extends JFrame {

    private PrintWriter pw;
    private Scanner scanner;
    private JPanel chatAndSend;
    private JTextArea chatWindow;
    private JScrollPane mainScroll;
    private JTextArea chatText;
    private JScrollPane miniScroll;
    private JButton send;
    private Socket client;

    public Client(String servername, int port) throws Exception {

        this.client = new Socket(servername, port);
        this.scanner = new Scanner(new InputStreamReader(
                this.client.getInputStream()));
        this.pw = new PrintWriter(this.client.getOutputStream());

        makeGUI();
        new MessagesThread().start();

    }

    public void makeGUI() {
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        getContentPane().setLayout(new BorderLayout());
        this.chatWindow = new JTextArea(10, 20);
        this.chatWindow.setEditable(false);
        this.chatWindow.setLineWrap(true);
        this.mainScroll = new JScrollPane(chatWindow,
                JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
                JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
        this.add(this.mainScroll, BorderLayout.NORTH);
        this.chatAndSend = new JPanel();
        this.chatAndSend.setLayout(new FlowLayout());
        this.chatText = new JTextArea(1, 1);
        this.chatText.setLineWrap(true);
        this.miniScroll = new JScrollPane(chatText,
                JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
                JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
        this.chatAndSend.add(this.miniScroll);
        this.send = new JButton();
        this.send.setText("SEND");
        this.send.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent event) {
                pw.println(chatText.getText());
                pw.flush();
            }
        });
        this.chatAndSend.add(this.send);
        this.add(this.chatAndSend, BorderLayout.SOUTH);
        this.setVisible(true);
        this.pack();
    }

    class MessagesThread extends Thread {
        public void run() {
            String line;
            try {
                while (true) {
                    line = scanner.nextLine();
                    chatWindow.append(line + "\n");
                }
            } catch (Exception exception) {
                System.out.println(exception.getMessage());
            }
        }
    }
    }

回答by Hovercraft Full Of Eels

  • In the Client MessagesThread class, in the while loop, it should be while (scanner.hasNextLine()) {
  • In the same class you are appending to a JTextArea from a background thread, something that you should not do.
  • In the Client MessagesThread class, implement Runnable rather than extend Thread (general recommendation)
  • Even better -- use a SwingWorker, so you can use publish/process to update the JTextArea on the Swing event thread.
  • For my money, I'd get the program up and running in a non-GUI version first before trying to put it into a GUI.
  • Your spelling errors suggest that the code shouldn't even compile, what with clientss, and clents,... ??? Is this your realcode? If we can't copy/paste your code and test it, we will have a tough time helping you.
  • 在Client MessagesThread类中,在while循环中,应该是 while (scanner.hasNextLine()) {
  • 在同一个类中,您从后台线程附加到 JTextArea,这是您不应该做的。
  • 在Client MessagesThread类中,实现Runnable而不是扩展Thread(一般推荐)
  • 更好——使用 SwingWorker,这样您就可以使用发布/处理来更新 Swing 事件线程上的 JTextArea。
  • 为了我的钱,我会先在非 GUI 版本中启动并运行程序,然后再尝试将其放入 GUI 中。
  • 您的拼写错误表明代码甚至不应该编译,客户和客户怎么办,......?这是你真正的代码吗?如果我们无法复制/粘贴您的代码并对其进行测试,我们将很难为您提供帮助。


Edit
I've looked at and run your new code. Do you see that you're trying to create a new Client in a catch block, one that is never called?

编辑
我已经查看并运行您的新代码。您是否看到您正在尝试在 catch 块中创建一个从未调用过的新客户端?

Most importantly -- use a debugger when running your code to see what your code is doing or is not doing. Add println statements as well (more of them). If you did this, you'd see that Client's constructor is never called, and would know to look at the code where you try to call it to see why.

最重要的是——在运行你的代码时使用调试器来查看你的代码在做什么或没有做什么。添加 println 语句(更多)。如果您这样做,您会看到 Client 的构造函数从未被调用,并且会知道查看您尝试调用它的代码以了解原因。

回答by croraf

Not sure if this is one of your problems, but i don't know if its safe to make a foreach loop in the Server class, cause you can iterate from one thread and add things to list from another in the same time, something that can be a problem to foreach loop. Please correct me if i'm wrong. (Or just deleting from foreach could harm it?)

不确定这是否是您的问题之一,但我不知道在 Server 类中进行 foreach 循环是否安全,因为您可以从一个线程进行迭代并同时将内容添加到另一个线程中foreach 循环可能是一个问题。如果我错了,请纠正我。(或者只是从 foreach 中删除可能会损害它?)