Reputation:
My question is as the title implies; my attempt of making an instant messenger handling multiple clients isn't working. I have tried using threading like every website says I should. I get a really weird result, though.
The server and the second client to join on pick up all of the messages. The first client to join on, however, doesn't pick up anything. Including it's own messages.
Here is my code:
Server:
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();
}
}
});
}
}
Client:
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);
}
}
Why isn't this working and how can I fix this? Thank you!
Upvotes: 0
Views: 59
Reputation: 21883
You need to learn Multi Thread Programming. You have created a static variable in your ServerThread
class to store the ObjectOutputStream
. Static variables are class level variables that means there will be a single variable for all instances of ServerThread
. So when the second client connects it will replace the ObjectOutputStream
in ServerThread
which is global. That is why your second client gets all the messages. For the moment you can make ServerThread.output
variable non static and change sendObject
method signature to public void sendObject(Object obj, final ObjectOutputStream output)
and call 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();
}
}
});
}
}
Upvotes: 1