Java即时消息程序,多个客户端无法正常工作

时间:2017-08-30 09:08:50

标签: java multithreading networking java-io

我的问题正如标题所暗示的那样;我尝试使用即时通讯工具处理多个客户端并不起作用。我尝试过使用线程,就像每个网站都说的那样。不过,我得到了一个非常奇怪的结果。

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

这是我的代码:

服务器:

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);
}

}

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

1 个答案:

答案 0 :(得分:1)

您需要学习多线程编程。您已在ServerThread类中创建了一个静态变量来存储ObjectOutputStream。静态变量是类级变量,这意味着ServerThread的所有实例都会有一个变量。因此,当第二个客户端连接时,它将替换全局ObjectOutputStream中的ServerThread。这就是为什么你的第二个客户端获取所有消息。目前,您可以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();
            }
        }
    });

}
}