我的问题正如标题所暗示的那样;我尝试使用即时通讯工具处理多个客户端并不起作用。我尝试过使用线程,就像每个网站都说的那样。不过,我得到了一个非常奇怪的结果。
要加入的服务器和第二个客户端获取所有消息。然而,第一个加入的客户并没有接受任何东西。包括它自己的消息。
这是我的代码:
服务器:
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);
}
}
为什么这不起作用,我该如何解决这个问题?谢谢!
答案 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();
}
}
});
}
}