【问题标题】:Java instant messenger with multiple clients not working具有多个客户端的 Java 即时通讯程序无法正常工作
【发布时间】:2018-02-07 22:14:41
【问题描述】:

我的问题正如标题所暗示的那样;我试图让即时通讯程序处理多个客户的尝试没有奏效。我尝试过使用每个网站都说我应该使用的线程。不过,我得到了一个非常奇怪的结果。

服务器和第二个加入的客户端接收所有消息。然而,第一个加入的客户并没有收到任何东西。包括它自己的消息。

这是我的代码:

服务器:

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;

import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;

public class Server extends JFrame {

JTextField userText;
static JTextArea dialog;

ServerSocket server;
Socket socket;

static boolean isClosed;

public Server() {
    super("server");

    addWindowListener(new WindowAdapter() {
        public void windowClosed(WindowEvent e) {
            isClosed = true;
        }
    });

        userText = new JTextField();
        userText.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                ServerThread.sendObject("\nSERVER: "+e.getActionCommand());
                log("\nSERVER: "+e.getActionCommand());
                userText.setText("");
            }
        });

        dialog = new JTextArea();
        dialog.setEditable(false);

        add(new JScrollPane(dialog),BorderLayout.CENTER);
        add(userText,BorderLayout.SOUTH);

        setSize(300,150);
        setVisible(true);
}

public static void main(String args[]) {
    Server s = new Server();
    s.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    s.initNetwork();
}

public void initNetwork() {
    try{
    server = new ServerSocket(1357);

    while(true) {
        try{

            ServerThread thread = new ServerThread(server.accept());
            thread.start();
        }catch(Exception eof) {
            System.out.println("Server disconnected");
        }
    }
    }catch(IOException io) {
        io.printStackTrace();
    }finally{
        try{
        server.close();
        }catch(IOException io) {
            io.printStackTrace();
        }
    }


}
public static void log(String msg) {
    dialog.append(msg);
}


}

class ServerThread extends Thread{

Socket connection;

ObjectInputStream input;
static ObjectOutputStream output;

String message;

public ServerThread(Socket s) {
    connection = s;
    try{
    setupStreams();
    }catch(IOException io) {
        io.printStackTrace();
    }
}

public void run() {
    try{
        readInput();
    }catch(IOException io) {
        io.printStackTrace();
    }finally{
        try{
        input.close();
        output.close();
        connection.close();
        }catch(IOException io) {
            io.printStackTrace();
        }
    }
}
public void setupStreams() throws IOException{
    input = new ObjectInputStream(connection.getInputStream());
    output = new ObjectOutputStream(connection.getOutputStream());
    output.flush();
}

public void readInput() throws IOException {
    while(!Server.isClosed) {
        try{
        message = (String)input.readObject();
        Server.log(message);
        sendObject(message);
        }catch(ClassNotFoundException c) {
            c.printStackTrace();
        }
    }
}

public static void sendObject(Object obj) {
    SwingUtilities.invokeLater(new Thread() {
        public void run() {
            try{
            output.writeObject(obj);
            }catch(IOException io) {
                io.printStackTrace();
            }
        }
    });

}
}

客户:

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;

import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;

public class Client extends JFrame{

JTextField userText;
static JTextArea dialog;

static boolean isClosed;

public Client() {
    super("client");
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    addWindowListener(new WindowAdapter() {
        public void windowClosed(WindowEvent e) {
            isClosed = true;
        }
    });

    userText = new JTextField();
    userText.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            sendObject("\nClient: "+e.getActionCommand());
            userText.setText("");
        }
    });


    dialog = new JTextArea();
    dialog.setEditable(false);

    add(userText,BorderLayout.SOUTH);
    add(new JScrollPane(dialog),BorderLayout.CENTER);

    setSize(300,150);
    setVisible(true);

    new ClientThread("127.0.0.1");
}

public static void main(String args[]) {
    Client c = new Client();
}
public void sendObject(Object obj) {
    try{
    ClientThread.output.writeObject(obj);
    }catch(IOException io) {
        io.printStackTrace();
    }
}
}

class ClientThread extends Thread{

private Socket socket;
private ObjectInputStream input;
static ObjectOutputStream output;

String message;

public ClientThread(String ip) {
    try{
        socket = new Socket(ip,1357);

        output = new ObjectOutputStream(socket.getOutputStream());
        output.flush();
        input = new ObjectInputStream(socket.getInputStream());

        start();

    }catch(IOException io) {
        io.printStackTrace();
    }
}

public void run() {
    try{
    while(!Client.isClosed) {
        try{
        message = (String)input.readObject();
        log(message);
        }catch(ClassNotFoundException c) {
            c.printStackTrace();
        }
    }
    }catch(IOException io) {
        io.printStackTrace();
    }finally{
        try{
            input.close();
            output.close();
            socket.close();
        }catch(IOException io) {
            io.printStackTrace();
        }
    }
}

public void log(String msg) {
    Client.dialog.append(msg);
}

}

为什么这不起作用,我该如何解决?谢谢!

【问题讨论】:

    标签: java multithreading networking java-io


    【解决方案1】:

    你需要学习多线程编程。您已经在ServerThread 类中创建了一个静态变量来存储ObjectOutputStream。静态变量是类级别的变量,这意味着ServerThread 的所有实例都有一个变量。因此,当第二个客户端连接时,它将替换全局的ServerThread 中的ObjectOutputStream。这就是为什么您的第二个客户会收到所有消息的原因。目前您可以将ServerThread.output 变量设为非静态变量并将sendObject 方法签名更改为public void sendObject(Object obj, final ObjectOutputStream output) 并调用sendObject(message, output);

    import javax.swing.JTextArea;
    import javax.swing.JTextField;
    import javax.swing.SwingUtilities;
    
    public class Server extends JFrame {
    
    JTextField userText;
    static JTextArea dialog;
    
    ServerSocket server;
    Socket socket;
    
    static boolean isClosed;
    
    public Server() {
        super("server");
    
        addWindowListener(new WindowAdapter() {
            public void windowClosed(WindowEvent e) {
                isClosed = true;
            }
        });
    
            userText = new JTextField();
            userText.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    ServerThread.sendObject("\nSERVER: "+e.getActionCommand());
                    log("\nSERVER: "+e.getActionCommand());
                    userText.setText("");
                }
            });
    
            dialog = new JTextArea();
            dialog.setEditable(false);
    
            add(new JScrollPane(dialog),BorderLayout.CENTER);
            add(userText,BorderLayout.SOUTH);
    
            setSize(300,150);
            setVisible(true);
    }
    
    public static void main(String args[]) {
        Server s = new Server();
        s.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        s.initNetwork();
    }
    
    public void initNetwork() {
        try{
        server = new ServerSocket(1357);
    
        while(true) {
            try{
    
                ServerThread thread = new ServerThread(server.accept());
                thread.start();
            }catch(Exception eof) {
                System.out.println("Server disconnected");
            }
        }
        }catch(IOException io) {
            io.printStackTrace();
        }finally{
            try{
            server.close();
            }catch(IOException io) {
                io.printStackTrace();
            }
        }
    
    
    }
    public static void log(String msg) {
        dialog.append(msg);
    }
    
    
    }
    
    class ServerThread extends Thread{
    
    Socket connection;
    
    ObjectInputStream input;
    ObjectOutputStream output;
    
    String message;
    
    public ServerThread(Socket s) {
        connection = s;
        try{
        setupStreams();
        }catch(IOException io) {
            io.printStackTrace();
        }
    }
    
    public void run() {
        try{
            readInput();
        }catch(IOException io) {
            io.printStackTrace();
        }finally{
            try{
            input.close();
            output.close();
            connection.close();
            }catch(IOException io) {
                io.printStackTrace();
            }
        }
    }
    public void setupStreams() throws IOException{
        input = new ObjectInputStream(connection.getInputStream());
        output = new ObjectOutputStream(connection.getOutputStream());
        output.flush();
    }
    
    public void readInput() throws IOException {
        while(!Server.isClosed) {
            try{
            message = (String)input.readObject();
            Server.log(message);
            sendObject(message, output);
            }catch(ClassNotFoundException c) {
                c.printStackTrace();
            }
        }
    }
    
    public void sendObject(Object obj, final ObjectOutputStream output) {
        SwingUtilities.invokeLater(new Thread() {
            public void run() {
                try{
                output.writeObject(obj);
                }catch(IOException io) {
                    io.printStackTrace();
                }
            }
        });
    
    }
    }
    

    【讨论】:

    • 感谢您的回答。但是,无法从 Server 类访问 OutputStream“输出”,那么如何从 TextField 事件侦听器访问它?
    猜你喜欢
    • 2023-04-02
    • 1970-01-01
    • 2017-08-17
    • 2017-09-23
    • 2018-10-12
    • 2020-06-17
    • 2021-07-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多