2017-08-30 82 views
0

我的问题与标题所暗示的一样;我试图让一个即时通讯软件处理多个客户端不起作用。我曾尝试使用线程,就像每个网站所说的那样。不过,我得到了一个非常奇怪的结果。有多个客户端无法使用的Java即时通讯

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

这里是我的代码:

服务器:

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

您需要学习多线程编程。您在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(); 
      } 
     } 
    }); 

} 
} 
+0

谢谢你的回答。但是,OutputStream'output'不能从Server类访问,所以我如何从TextField事件侦听器访问它? – Max