I have a multi-thread chatroom that connects to one server. They all connect, login, and message independently of each other just fine, but when I log off with one of the clients (and the server does a socket.close() for that instance of the client) all clients are logged off. I looked at a bunch of other questions on stackoverflow before posting this, but none of them had the same issue as mine (that I found). Note: All the clients were running locally on my computer, 2+ of them, and that's how I encountered the bug. Could them being on the same IP (though everything is done on my localhost..) cause this to happen? Any help or insight as to what is causing this issue and how I could resolve it would be great. When the issue occurs it also outputs this to the console:
Socket: Socket[addr=localhost/127.0.0.1,port=4000,localport=55650]
Here is the code (how to recreate the bug is at the bottom):
Server class:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashSet;
public class ChatServer {
private static final int PORT = 4000;
private static HashSet<String> names = new HashSet<String>();
private static HashSet<ObjectOutputStream> outputs =
new HashSet<ObjectOutputStream>();
public static void main(String[] args) throws IOException{
System.out.println("The chat server is running...");
ServerSocket listener = new ServerSocket(PORT);
while(true){
new Handler(listener.accept()).start();
}
}
private static class Handler extends Thread{
private String name;
private Socket socket;
private ObjectInputStream in;
private ObjectOutputStream out;
private boolean loggedOut;
public Handler(Socket socket){
this.socket = socket;
}
public void run(){
try {
out = new ObjectOutputStream(socket.getOutputStream());
in = new ObjectInputStream(socket.getInputStream());
loggedOut = false;
while(true){
Message message = (Message) in.readObject();
System.out.println("Server recieved login message!");
if(message.getNumber() == 0){
name = message.getName();
synchronized(names){
if(!names.contains(name)){
names.add(name);
break;
}else{
Message nameTaken = new Message(null, 3);
sendMessage(out, nameTaken);
}
}
}
}
synchronized(outputs){
outputs.add(out);
}
for(ObjectOutputStream output: outputs){
Message response = new Message(name, name + " has logged on.", 0);
sendMessage(output, response);
}
while(true){
System.out.println("Waiting for message...");
Message message = (Message) in.readObject();
Message response = null;
if(message.getNumber() == 1 && message.getMessage() != null){
response = new Message(message.getName(),
message.getMessage(), 1);
}else if(message.getNumber() == 2){
response = new Message(message.getName(), message.getName() +
" has logged off.", 2);
loggedOut = true;
}
for(ObjectOutputStream output: outputs){
sendMessage(output, response);
}
if(loggedOut) break;
}
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}finally {
if(name != null) names.remove(name);
if(out != null) outputs.remove(out);
try{
socket.close();
}catch(IOException e){
e.printStackTrace();
}
}
}
private void sendMessage(ObjectOutputStream out, Message message){
ObjectOutputStream outPutMessage = out;
Message response = message;
try {
outPutMessage.writeObject(response);
outPutMessage.flush();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
}
Client class:
import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.ArrayList;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
public class ChatClient extends JFrame {
private JTextField inputField;
private JTextField nameField;
private JTextArea textArea;
private JButton loginButton;
private JButton logoutButton;
private JButton connectButton;
private JScrollPane textScroll;
private JScrollPane listScroll;
private JPanel textPanel;
private JPanel connectPanel;
private JPanel listPanel;
private JPanel inputPanel;
private JPanel namePanel;
private JPanel inputAndDisplayPanel;
private JPanel listAndLogoutPanel;
private ArrayList<String> stringList;
private JList list;
private final int CELL_WIDTH = 100;
private ObjectOutputStream out;
private ObjectInputStream in;
private JFrame chatFrame;
private ChatClient client;
private String name;
private final int PORT = 4000;
private boolean needServerData;
private boolean loggedIn;
private boolean previouslyLoggedIn;
private String serverAddress = null;
private Socket socket = null;
private void run() throws IOException, ClassNotFoundException{
needServerData = true;
loggedIn = true;
while(true){
//Loops before a user is logged in, verifies that the host is usable
while (socket == null) {
if (needServerData) {
try {
connectButton.setEnabled(false);
serverAddress = JOptionPane.showInputDialog(client,
"Enter server address: ", "Server Address",
JOptionPane.QUESTION_MESSAGE);
if(serverAddress == null){
JOptionPane.showMessageDialog(client,
"Click 'Connect' to re-enter server address.",
"Info", JOptionPane.PLAIN_MESSAGE);
needServerData = false;
connectButton.setEnabled(true);
}else if(serverAddress.equals("")){
JOptionPane.showMessageDialog(client,
"Invalid input! Enter a valid server address.",
"Error", JOptionPane.ERROR_MESSAGE);
}else {
socket = new Socket(serverAddress, PORT);
out = new ObjectOutputStream(socket.getOutputStream());
in = new ObjectInputStream(socket.getInputStream());
loginButton.setEnabled(true);
logoutButton.setEnabled(false);
nameField.setEnabled(true);
connectButton.setEnabled(false);
}
} catch (UnknownHostException e1) {
JOptionPane.showMessageDialog(client,
"Error: Unknown host!", "Error",
JOptionPane.ERROR_MESSAGE);
}
}
}
/*Loops after the user is logged in (will output to the textarea that that user logged in),
* reads in messages from server to append to the textarea and also determines if a user is
* logging out. Changes editable/enabled of buttons and text fields accordingly.
*/
if(loggedIn) {
Message message = (Message) in.readObject();
if (message.getNumber() == 1) {
textArea.append(message.getName() + ": "
+ message.getMessage() + "\n");
} else if (message.getNumber() == 0) {
inputField.setEditable(true);
textArea.append(message.getMessage() + "\n");
loginButton.setEnabled(false);
logoutButton.setEnabled(true);
} else if (message.getNumber() == 2) {
inputField.setText(null);
inputField.setEditable(false);
nameField.setText(null);
nameField.setEnabled(false);
connectButton.setEnabled(true);
logoutButton.setEnabled(false);
loggedIn = false;
previouslyLoggedIn = true;
textArea.append(message.getMessage() + "\n");
System.out.println("Socket: " + socket);
} else {
JOptionPane.showMessageDialog(client,
"Error: That name is taken!", "Error",
JOptionPane.ERROR_MESSAGE);
}
}
}
}
private String getServerAddress(){
return JOptionPane.showInputDialog(client, "Enter server address: ",
"Server Address", JOptionPane.QUESTION_MESSAGE);
}
public static void main(String[] args) throws IOException, ClassNotFoundException{
ChatClient client = new ChatClient();
try {
client.run();
} catch (IOException e) {
e.printStackTrace();
}
}
public ChatClient(){
//GUI Formatting Stuff
inputField = new JTextField(30);
nameField = new JTextField(10);
textArea = new JTextArea(25, 30);
loginButton = new JButton("Login");
logoutButton = new JButton("Logout");
connectButton = new JButton("Connect");
textScroll = new JScrollPane(textArea,
JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
textPanel = new JPanel();
listPanel = new JPanel();
inputPanel = new JPanel();
namePanel = new JPanel();
connectPanel = new JPanel();
textArea.setEditable(false);
textPanel.add(textScroll);
stringList = new ArrayList<String>();
list = new JList(stringList.toArray());
list.setFixedCellWidth(CELL_WIDTH);
listScroll = new JScrollPane(list);
listPanel.add(listScroll);
listAndLogoutPanel = new JPanel(new BorderLayout());
listAndLogoutPanel.add(listPanel, BorderLayout.CENTER);
listAndLogoutPanel.add(logoutButton, BorderLayout.SOUTH);
listAndLogoutPanel.add(loginButton, BorderLayout.NORTH);
inputField.setEditable(false);
inputPanel.add(inputField);
inputAndDisplayPanel = new JPanel(new BorderLayout());
inputAndDisplayPanel.add(textPanel, BorderLayout.CENTER);
inputAndDisplayPanel.add(inputPanel, BorderLayout.SOUTH);
nameField.setEnabled(false);
loginButton.setEnabled(false);
logoutButton.setEnabled(false);
namePanel.setLayout(new FlowLayout(FlowLayout.LEFT));
namePanel.add(new JLabel("Name: "));
namePanel.add(nameField);
connectPanel.add(connectButton);
JPanel topPanel = new JPanel(new BorderLayout());
topPanel.add(namePanel, BorderLayout.WEST);
topPanel.add(connectPanel, BorderLayout.EAST);
JPanel centerPanel = new JPanel(new BorderLayout());
centerPanel.add(inputAndDisplayPanel, BorderLayout.CENTER);
centerPanel.add(topPanel, BorderLayout.NORTH);
JPanel eastPanel = new JPanel(new BorderLayout());
eastPanel.add(listAndLogoutPanel, BorderLayout.CENTER);
setLayout(new BorderLayout());
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
add(centerPanel, BorderLayout.CENTER);
add(eastPanel, BorderLayout.EAST);
pack();
setLocationRelativeTo(null);
//Listeners
loginButton.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent e) {
name = nameField.getText();
if(name.trim().length() < 3 || name.length() > 15 || name == null){
JOptionPane.showMessageDialog(client,
"Error: Name must be between 3 and 15 characters long.", "Error",
JOptionPane.ERROR_MESSAGE);
}else{
Message message = new Message(name, 0);
try {
out.writeObject(message);
out.flush();
} catch (IOException e1) {
e1.printStackTrace();
}
loggedIn = true;
}
}
});
connectButton.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent arg0) {
needServerData = true;
if(previouslyLoggedIn) socket = null;
}
});
inputField.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent arg0) {
Message message = new Message(name, inputField.getText(), 1);
try {
out.writeObject(message);
out.flush();
} catch (IOException e1) {
e1.printStackTrace();
}
inputField.setText(null);
}
});
logoutButton.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent arg0) {
Message message = new Message(name, 2);
try {
out.writeObject(message);
out.flush();
} catch (IOException e1) {
e1.printStackTrace();
}
inputField.setText(null);
}
});
}
}
Message class:
import java.io.Serializable;
public class Message implements Serializable{
private int number;
private String message;
private String name;
public Message(String name, int number){
this.name = name;
this.number = number;
}
public Message(String name, String message, int number){
this.message = message;
this.number = number;
this.name = name;
}
public boolean isLogin(){
if(number == 0) return true;
return false;
}
public boolean isMessage(){
if(number == 1) return true;
return false;
}
public boolean isLogout(){
if(number == 2) return true;
return false;
}
public int getNumber() {
return number;
}
public String getMessage() {
return message;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
I know this is a big block of code and not that neatly documented/formatted, so I apologize for that. I'm just posting the whole thing so you can duplicate the problem by running the code in it's entirety. Additionally, ignore the JList as I haven't gotten to that yet since I encountered and haven't been able to resolve the logging off/socket issue. To recreate the bug, go through the following steps:
Run the Server class
Run a client class, enter "localhost" as the server address, then enter a name and click log-in
Run another client class and follow step 2
Click log-off on one of the client classes, and you'll see the other is also logged off.
Thanks in advance for any help, I appreciate it!
In your ChatClient class, you need to change the line
} else if (message.getNumber() == 2) {
to
} else if (message.getNumber() == 2 && message.getName().equals(name)) {
Because the way it is currently, each chat client receives the message that a client has been logged out, and each client is responding to that by logging out. You will need to handle the additional case afterwards that message.getNumber() == 2, because as it stands now you will assume that it means the name was taken.
Related
I am creating a multiclient chat server program. Messages are sent as Message objects. The ServerClient class is not recieving the messages, though, and I don't know why.
Client:
package client;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import javax.swing.*;
import constraints.Constraints;
import message.Message;
import tools.Tools;
import window.ApplicationWindow;
#SuppressWarnings("serial")
public class Client extends ApplicationWindow {
private static final int portNumber = 4444;
private boolean send = false;
private String userName;
private String serverHost;
private int serverPort;
private GridBagLayout layout;
private JTextArea textArea;
private Constraints c_textArea;
private JTextField textField;
private Constraints c_textField;
public static void main(String[] args){
String readName = System.getProperty("user.name");
Client client = new Client(readName, portNumber);
client.startClient();
}
private Client(String userName, int portNumber){
super("ChatApp");
Tools.setLookAndFeel();
this.userName = userName;
this.serverPort = portNumber;
try {
this.serverHost = InetAddress.getLocalHost().getHostAddress();
}catch(Exception e) {
}
layout = new GridBagLayout();
setLayout(layout);
textArea = new JTextArea();
textArea.setColumns(75);
textArea.setRows(20);
c_textArea = new Constraints(0,1);
textArea.setLineWrap(true);
textArea.setEditable(false);
textArea.setVisible(true);
JScrollPane scroll = new JScrollPane (textArea);
scroll.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
add(scroll, c_textArea);
textField = new JTextField();
textField.setColumns(50);
textField.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
send = true;
}
});
c_textField = new Constraints(0,2);
add(textField, c_textField);
pack();
setVisible(true);
setResizable(false);
}
public void output(String message) {
this.textArea.setText(this.textArea.getText() + "\n" + message);
}
private void startClient() {
try{
Socket socket = new Socket(serverHost, serverPort);
Thread.sleep(1000);
ServerThread serverThread = new ServerThread(socket, userName, this);
Thread serverAccessThread = new Thread(serverThread);
serverAccessThread.start();
while(serverAccessThread.isAlive() && this.isRunning()) {
if (send) {
Message message = new Message(textField.getText(), "[" + "]", this.userName);
serverThread.addNextMessage(message);
send = false;
textField.setText("");
}
Thread.sleep(200);
}
}catch(IOException ex){
output("Could not connect to server!");
}catch(InterruptedException ex){
output("Connection interrupted!");
}
}
public void setHost(String serverHost) {
this.serverHost = serverHost;
}
}
ServerClient:
package server;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.SocketException;
import java.util.Scanner;
import message.Message;
public class ServerClient implements Runnable {
private Socket socket;
private PrintWriter clientOut;
private ChatServer server;
private boolean running;
public ServerClient(ChatServer server, Socket socket) {
this.server = server;
this.socket = socket;
this.running = true;
}
private PrintWriter getWriter(){
return clientOut;
}
public boolean isRunning() {
return this.running;
}
public void stop() {
this.running = false;
}
#Override
public void run() {
try{
this.clientOut = new PrintWriter(socket.getOutputStream(), false);
clientOut.flush();
ObjectInputStream in = new ObjectInputStream(socket.getInputStream());
while(!socket.isClosed()){
try {
if (in.available() > 0) {
Object i = in.readObject();
if (!i.equals(null)) {
Message input = (Message) i;
String message = input.getText();
String time = input.getTimestamp();
String user = input.getUser();
for(ServerClient thatClient : server.getClients()){
PrintWriter thatClientOut = thatClient.getWriter();
if(thatClientOut != null){
thatClientOut.write(time + " " + user + ": " + message + "\r\n");
thatClientOut.flush();
}
}
}
}
} catch (ClassNotFoundException e) {
System.out.println(e);
} catch (SocketException ex) {
System.out.println(ex);
break;
}
}
in.close();
this.stop();
} catch (IOException e) {
e.printStackTrace();
}
}
//public void fileWrite()
}
ChatServer:
package server;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;
//import javax.swing.JComboBox;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import constraints.Constraints;
import tools.Tools;
import window.ApplicationWindow;
import message.Message;
#SuppressWarnings("serial")
public class ChatServer extends ApplicationWindow {
private static final int portNumber = 4444;
private ArrayList<Command> commands;
private int serverPort;
private String serverHost;
private List<ServerClient> clients;
ServerSocket serverSocket;
private GridBagLayout layout;
private JTextArea textArea;
private Constraints c_textArea;
private JTextField textField;
private Constraints c_textField;
public static void main(String[] args){
ChatServer server = new ChatServer(portNumber);
server.startServer();
}
public ChatServer(int portNumber){
super("Server " + portNumber);
this.serverPort = portNumber;
try {
this.serverHost = InetAddress.getLocalHost().getHostAddress();
} catch (UnknownHostException e) {
this.serverHost = "";
}
Tools.setLookAndFeel();
initActions();
layout = new GridBagLayout();
setLayout(layout);
textArea = new JTextArea();
textArea.setColumns(75);
textArea.setRows(20);
c_textArea = new Constraints(0,1);
textArea.setLineWrap(true);
textArea.setEditable(false);
textArea.setVisible(true);
JScrollPane scroll = new JScrollPane (textArea);
scroll.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
add(scroll, c_textArea);
textField = new JTextField();
textField.setColumns(50);
textField.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
process(textField.getText());
}
});
c_textField = new Constraints(0,2);
add(textField, c_textField);
pack();
setVisible(true);
setResizable(false);
}
public List<ServerClient> getClients(){
return clients;
}
private void startServer(){
clients = new ArrayList<ServerClient>();
serverSocket = null;
try {
InetAddress addr = InetAddress.getByName(this.serverHost);
serverSocket = new ServerSocket(serverPort, 50, addr);
acceptClients(serverSocket);
} catch (IOException e){
output("[ERROR] COULD NOT LISTEN ON PORT: " + serverPort);
this.stop();
}
}
private void acceptClients(ServerSocket serverSocket){
output("[BEGIN] SERVER STARTING ON PORT: " + serverSocket.getLocalSocketAddress());
while (this.isRunning()) {
try{
Socket socket = serverSocket.accept();
output("[ACCEPT] ACCEPTED CLIENT AT: " + socket.getRemoteSocketAddress());
ServerClient client = new ServerClient(this, socket);
Thread thread = new Thread(client);
thread.start();
clients.add(client);
} catch (IOException ex) {
output("[ERROR] ACCEPT FAILED ON: " + serverPort);
}
}
}
private void initActions() {
this.commands = new ArrayList<Command>();
this.commands.add(new Command() {
public void run() {
output("[COMMAND] IP: " + serverSocket.getInetAddress().toString());
}
public String getTrigger() {
return "-ip";
}
});
this.commands.add(new Command() {
public void run() {
for (ServerClient client : clients) {
if (!client.isRunning()) {
clients.remove(client);
}
}
output("[COMMAND] CLIENTS: " + clients.size());
}
public String getTrigger() {
return "-clients";
}
});
}
public boolean process(String command) {
for (Command c : this.commands) {
if (c.getTrigger().equals(command)) {
c.run();
textField.setText("");
return true;
}
}
return false;
}
public void output(String message) {
this.textArea.setText(this.textArea.getText() + "\n" + message);
}
}
ServerThread:
package client;
import java.io.*;
import java.net.Socket;
import java.util.LinkedList;
import java.util.Scanner;
import message.Message;
#SuppressWarnings("unused")
public class ServerThread implements Runnable {
private Socket socket;
private String userName;
private boolean isAlived;
private final LinkedList<Message> messagesToSend;
private boolean hasMessages = false;
private Client client;
public ServerThread(Socket socket, String userName, Client client){
this.socket = socket;
this.userName = userName;
this.client = client;
messagesToSend = new LinkedList<Message>();
}
public void addNextMessage(Message message) {
synchronized (messagesToSend) {
hasMessages = true;
messagesToSend.push(message);
}
}
#Override
public void run(){
print("Welcome :" + userName);
print("Local Port :" + socket.getLocalPort());
print("Server = " + socket.getRemoteSocketAddress() + ":" + socket.getPort());
try {
ObjectOutputStream serverOut = new ObjectOutputStream(socket.getOutputStream());
serverOut.flush();
ObjectInputStream serverIn = new ObjectInputStream(socket.getInputStream());
while(!socket.isClosed()){
if (serverIn.available() > 0) {
try {
if (serverIn.readObject() != null) {
Message input = (Message) serverIn.readObject();
}
} catch (ClassNotFoundException e) {
System.out.println(e);
}
}
if(hasMessages){
Message nextSend;
synchronized(messagesToSend){
nextSend = messagesToSend.pop();
hasMessages = !messagesToSend.isEmpty();
}
serverOut.writeObject(nextSend);
serverOut.flush();
}
}
serverOut.close();
serverIn.close();
} catch(Exception ex){
ex.printStackTrace();
}
}
public void print(String message) {
this.client.output(message);
}
}
I know that the client is able to connect to the server, and both can get messages and successfully call the writeObject() method. However, the message never gets recieved. Can someone help me?
while(!socket.isClosed()){
if (serverIn.available() > 0) {
try {
if (serverIn.readObject() != null) {
Message input = (Message) serverIn.readObject();
}
} catch (ClassNotFoundException e) {
System.out.println(e);
}
}
if(hasMessages){
Message nextSend;
synchronized(messagesToSend){
nextSend = messagesToSend.pop();
hasMessages = !messagesToSend.isEmpty();
}
serverOut.writeObject(nextSend);
serverOut.flush();
}
}
This is all nonsense.
isClosed() returns true when you have closed the socket. Not when the peer disconnects.
Calling available() here and merely spin-looping while it is false is just literally a waste of time.
ObjectInputStream.readObect() only returns null if you send a null.
You are calling it twice, throwing the first object read away, and then trying to read the next object. So you are throwing away every odd-numbered object.
It should be more like this:
for (;;) {
try {
Message input = (Message) serverIn.readObject();
// process input here
} catch (EOFException e) {
break;
} catch (ClassNotFoundException e) {
System.out.println(e);
}
}
if(hasMessages){
Message nextSend;
synchronized(messagesToSend){
nextSend = messagesToSend.pop();
hasMessages = !messagesToSend.isEmpty();
}
serverOut.writeObject(nextSend);
serverOut.flush();
}
}
You should probably split this into a reading thread and a writing thread, as writeObject() and flush() can also block. Same remarks apply to the other place where you are using isClosed(), available(), testing for null, etc.
The hasMessages flag is also not going to work. It will remain false even though a message got added subsequently. It would be better to delete it and just rely on messagesToSend.isEmpty(), inside a synchronized block:
synchronized(messagesToSend){
while (!messagesToSend.isEmpty()){
Message nextSend = messagesToSend.pop();
serverOut.writeObject(nextSend);
}
}
serverOut.flush();
I'm trying to write a poker server and client program, I create the game in the server class and my client class takes the output and displays them. However, when ever i do this, there seem to be two game objects created, the first player gets the input that is consistent with the object that is shown in the console, the second player always displays cards that are not shown in the sysout method, and I can not seem to find where I created the second game object.
server class:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.HashSet;
public class PokerServer {
/**
* The port that the server listens on.
*/
private static final int PORT = 9050;
// keeps track of all the names
private static ArrayList<String> names = new ArrayList<String>();
// broadcast messages
private static ArrayList<PrintWriter> writers = new ArrayList<PrintWriter>();
private boolean bothPlayersConnected = false;
/**
* The appplication main method, which just listens on a port and spawns
* handler threads.
*/
public static void main(String[] args) throws Exception {
System.out.println("The poker server is running.");
ServerSocket listener = new ServerSocket(PORT);
try {
while (true) {
new GameThread(listener.accept()).start();
}
} finally {
listener.close();
}
}
private static class GameThread extends Thread {
private String name;
private Socket socket;
private BufferedReader in;
private PrintWriter out;
private Game game;
public GameThread(Socket socket) {
this.socket = socket;
}
/**
* Services this thread's client by repeatedly requesting a screen name
* until a unique one has been submitted, then acknowledges the name and
* registers the output stream for the client in a global set, then
* repeatedly gets inputs and broadcasts them.
*/
public void run() {
try {
System.out.println("get to this part");
// Create character streams for the socket.
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
out = new PrintWriter(socket.getOutputStream(), true);
// get the name of the player
out.println("SUBMITNAME");
name = in.readLine();
names.add(name);
while(names.size()<2){
out.println("MESSAGE waiting for opponent to connect");
}
// Now that a successful name has been chosen, add the
// socket's print writer to the set of all writers so
// this client can receive broadcast messages.
// out.println("NAMEACCEPTED");
// writers.add(out);
game = new Game(names.get(0), names.get(1), 1000);
game.dealToPlayers();
out.println(names.get(0) + game.getPlayer1().getHand()[0].transferStr());
out.println(names.get(0) + game.getPlayer1().getHand()[1].transferStr());
out.println(names.get(1) + game.getPlayer2().getHand()[0].transferStr());
out.println(names.get(1) + game.getPlayer2().getHand()[1].transferStr());
// Accept messages from this client and broadcast them.
// Ignore other clients that cannot be broadcasted to.
while (true) {
String input = in.readLine();
if (input == null) {
return;
} else if (input.startsWith(names.get(0))) {
}
for (PrintWriter writer : writers) {
writer.println("MESSAGE " + name + ": " + input);
}
}
} catch (IOException e) {
System.out.println(e);
} finally {
// This client is going down! Remove its name and its print
// writer from the sets, and close its socket.
if (name != null) {
names.remove(name);
}
if (out != null) {
writers.remove(out);
}
try {
socket.close();
} catch (IOException e) {
}
}
}
}
}
Client class
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
public class PokerClient {
BufferedReader in;
PrintWriter out;
String playerName = "Poker";
JFrame frame = new JFrame(playerName);
JPanel playerHandPanel, controlPanel, bottomPanel, topPanel, messageBoard;
JButton check, fold;
JTextField textField = new JTextField(10);
JLabel firstLine = new JLabel("");
String serverAddress = "localhost";
Card playerHand1, playerHand2;
public PokerClient() {
// Layout GUI
frame.setSize(1100, 700);
frame.setResizable(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
playerHandPanel = new JPanel(new GridLayout(1, 0));
playerHandPanel.setPreferredSize(new Dimension(600, 300));
playerHandPanel.setVisible(true);
topPanel = new JPanel(new GridLayout(1, 0));
topPanel.setPreferredSize(new Dimension(900, 300));
topPanel.setVisible(true);
messageBoard = new JPanel(new GridLayout(0, 1));
messageBoard.add(firstLine);
controlPanel = new JPanel();
controlPanel.setPreferredSize(new Dimension(600, 40));
controlPanel.setVisible(true);
topPanel.add(messageBoard);
check = new JButton("Check");
check.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
out.println(playerName+"CHECK");
}
});
fold = new JButton("fold");
fold.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
out.println(playerName+"FOLD");
}
});
textField.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if(isInt(textField.getText())){
out.println(textField.getText());
textField.setText("");
} else{
JFrame frame = new JFrame("Not a number");
frame.setSize(600, 70);
frame.setLocation(400, 250);
frame.setResizable(false);
JLabel label = new JLabel("You must enter a number in order to raise");
frame.add(label);
frame.setVisible(true);
frame.toFront();
frame.repaint();
textField.setText("");
}
}
});
controlPanel.add(check);
controlPanel.add(fold);
controlPanel.add(new JLabel(" Raise:"));
controlPanel.add(textField);
bottomPanel = new JPanel();
bottomPanel.add(controlPanel, BorderLayout.SOUTH);
bottomPanel.add(playerHandPanel, BorderLayout.NORTH);
frame.add(topPanel, BorderLayout.NORTH);
frame.add(bottomPanel, BorderLayout.SOUTH);
//frame.add(firstLine, "SOUTH");
frame.setVisible(true);
}
private static boolean isInt(String s)
{
try
{ int i = Integer.parseInt(s); return true; }
catch(NumberFormatException er)
{ return false; }
}
/**
* Prompt for and return the desired screen name.
*/
private String getName() {
return JOptionPane.showInputDialog(
frame,
"Choose a screen name:",
"Screen name selection",
JOptionPane.PLAIN_MESSAGE);
}
private Card constructCard(String line){
int seperator = line.indexOf('/');
int cardNum = Integer.parseInt(line.substring(0, seperator));
Card card;
if(line.substring(seperator+1).startsWith("S")){
card = new Card(cardNum, Suit.SPADE);
} else if(line.substring(seperator+1).startsWith("C")){
card = new Card(cardNum, Suit.CLUB);
} else if(line.substring(seperator+1).startsWith("D")){
card = new Card(cardNum, Suit.DIAMOND);
} else{
card = new Card(cardNum, Suit.HEART);
}
System.out.println(card.toString());
return card;
}
/**
* Connects to the server then enters the processing loop.
*/
private void run() throws IOException {
Socket socket = new Socket(serverAddress, 9050);
in = new BufferedReader(new InputStreamReader(
socket.getInputStream()));
out = new PrintWriter(socket.getOutputStream(), true);
// Process all messages from server, according to the protocol.
while (true) {
String line = in.readLine();
System.out.println(line);
if (line.startsWith("SUBMITNAME")) {
String name = getName();
playerName = name;
out.println(name);
frame.setTitle(playerName);
} else if (line.startsWith(playerName)) {
playerHandPanel.add(new CardComponent(constructCard(line.substring(playerName.length()))));
playerHandPanel.revalidate();
playerHandPanel.repaint();
} else if(line.startsWith("CARD")){
topPanel.add(new CardComponent(constructCard(line.substring(4))));
topPanel.revalidate();
topPanel.repaint();
} else if(line.startsWith("MESSAGE")){
firstLine.setText(line.substring(7));
}
}
}
public static void main(String[] args) throws Exception {
PokerClient client = new PokerClient();
client.frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
client.frame.setVisible(true);
client.run();
}
}
Consider the following class that just gets an IP and port number :
package view;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.net.InetAddress;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
/**
* Server side
* #author X
*
*/
class ServerConnector implements ActionListener
{
private JFrame m_frame = null;
private JTextField m_serverIP;
private JTextField m_serverPort; // you can use also JPasswordField
private JButton m_submitButton;
// location of the jframe
private final int m_centerX = 500;
private final int m_centerY = 300;
// dimensions of the jframe
private final int m_sizeX = 1650;
private final int m_sizeY = 150;
private String m_ip;
private String m_port;
private boolean ready = false;
/**
* Ctor
*/
ServerConnector()
{
m_frame = new JFrame("Sever Side Listener");
m_frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
m_serverIP = new JTextField(20);
m_serverPort = new JTextField(20);
JPanel gui = new JPanel(new BorderLayout(3,3));
gui.setBorder(new EmptyBorder(5,5,5,5));
gui.setSize(m_sizeX , m_sizeY);
m_frame.setContentPane(gui);
JPanel labels = new JPanel(new GridLayout(0,1));
JPanel controls = new JPanel(new GridLayout(0,1));
gui.add(labels, BorderLayout.WEST);
gui.add(controls, BorderLayout.CENTER);
labels.add(new JLabel("Server IP: "));
controls.add(m_serverIP);
labels.add(new JLabel("Server Port: "));
controls.add(m_serverPort);
m_submitButton = new JButton("Start Listening");
m_submitButton.addActionListener(this);
gui.add(m_submitButton, BorderLayout.SOUTH);
m_frame.setLocation(m_centerX , m_centerY);
m_frame.setSize(m_sizeX , m_sizeY);
m_frame.pack();
m_frame.setVisible(true);
}
public static void main(String[] args) {
new ServerConnector();
}
#Override
public void actionPerformed(ActionEvent event) {
Object object = event.getSource();
if (object == this.m_submitButton)
{
// grab all values from the connection box
// if one of them is missing then display an alert message
String ip = this.m_serverIP.getText().trim();
String port = this.m_serverPort.getText().trim();
if (ip.length() == 0)
{
JOptionPane.showMessageDialog(null, "Please enter IP address !");
return;
}
if (port.length() == 0)
{
JOptionPane.showMessageDialog(null, "Please enter Port number!");
return;
}
int s_port = 0;
try
{
// try parse the Port number
// throws exception when an incorrect IP address
// is entered , and caught in the catch block
s_port = Integer.parseInt(port);
}
catch(Exception exp)
{
JOptionPane.showMessageDialog(null, "Port number is incorrect!");
return;
}
try
{
// try parse the IP address
// throws exception when an incorrect IP address
// is entered , and caught in the catch block
InetAddress.getByName(ip);
}
catch(Exception exp)
{
JOptionPane.showMessageDialog(null, "IP address is incorrect!");
return;
}
m_frame.dispose();
this.m_ip = ip;
this.m_port = port;
ready = true;
// new ServerGUI(ip , s_port);
}
}
public boolean isReady()
{
return this.ready;
}
/**
*
* #return
*/
public String[] getIPandPort()
{
String[] ipPort = new String[2];
ipPort[0] = this.m_ip;
ipPort[1] = this.m_port;
return ipPort;
}
}
And the would be controller class
public class ServerController {
String m_ip;
int m_port;
public static void main(String args[])
{
ServerConnector sc = new ServerConnector();
while (!sc.isReady())
{
// run
}
// get IP and port
String[] ipPort = sc.getIPandPort();
System.out.println("IP is :" + ipPort[0] + " and port is :" + ipPort[1]);
}
}
For now ServerController is in a while(true) loop , until the user has entered the IP and Port.
How can I avoid this kind of dependency (avoid the while loop) ?
First of all, get rid of the while (true) loop as its only purpose will be to mess your code up.
A general solution is to get the information from the user in code that blocks program flow. A problem occurs, though if this is needed in a GUI that cannot have its event thread blocked.
One Swing solution is as we have discussed previously in your previous question: use a modal dialog to get the information. The modality of the dialog will halt the program flow in the calling code until the dialog is handled.
If you want to avoid use of modal dialogs, then another general event-driven solution is to use a observer design pattern -- have one object be notified by another when information or state has changed. This can be achieved easily with use of PropertyChangeSupport and PropertyChangeListeners, although there are other ways as well, including using the XxxxListeners available in the Swing library.
For example of listener use and MVC with Swing:
Modifying independent JPanels from the JFrame
Java keeps adding buttons! - JFrames
Edit
For example, changes marked with a // !! comment:
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.net.InetAddress;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import javax.swing.event.SwingPropertyChangeSupport;
public class ServerController {
String m_ip;
int m_port;
private static String[] ipPort;
public static void main(String args[]) {
final ServerConnector sc = new ServerConnector();
sc.addPropertyChangeListener(new PropertyChangeListener() {
#Override
public void propertyChange(PropertyChangeEvent evt) {
if (ServerConnector.READY.equals(evt.getPropertyName())) {
if (sc.isReady()) {
ipPort = sc.getIPandPort();
System.out.println("IP is :" + ipPort[0] + " and port is :" + ipPort[1]);
}
}
}
});
}
}
class ServerConnector implements ActionListener {
public static final String READY = "ready"; //!!
private SwingPropertyChangeSupport pcSupport = new SwingPropertyChangeSupport(this); //!!
private boolean ready = false;
private JFrame m_frame = null;
private JTextField m_serverIP;
private JTextField m_serverPort; // you can use also JPasswordField
private JButton m_submitButton;
// location of the jframe
private final int m_centerX = 500;
private final int m_centerY = 300;
// dimensions of the jframe
private final int m_sizeX = 1650;
private final int m_sizeY = 150;
private String m_ip;
private String m_port;
/**
* Ctor
*/
ServerConnector() {
m_frame = new JFrame("Sever Side Listener");
m_frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
m_serverIP = new JTextField(20);
m_serverPort = new JTextField(20);
JPanel gui = new JPanel(new BorderLayout(3, 3));
gui.setBorder(new EmptyBorder(5, 5, 5, 5));
gui.setSize(m_sizeX, m_sizeY);
m_frame.setContentPane(gui);
JPanel labels = new JPanel(new GridLayout(0, 1));
JPanel controls = new JPanel(new GridLayout(0, 1));
gui.add(labels, BorderLayout.WEST);
gui.add(controls, BorderLayout.CENTER);
labels.add(new JLabel("Server IP: "));
controls.add(m_serverIP);
labels.add(new JLabel("Server Port: "));
controls.add(m_serverPort);
m_submitButton = new JButton("Start Listening");
m_submitButton.addActionListener(this);
gui.add(m_submitButton, BorderLayout.SOUTH);
m_frame.setLocation(m_centerX, m_centerY);
m_frame.setSize(m_sizeX, m_sizeY);
m_frame.pack();
m_frame.setVisible(true);
}
public static void main(String[] args) {
new ServerConnector();
}
#Override
public void actionPerformed(ActionEvent event) {
Object object = event.getSource();
if (object == this.m_submitButton) {
// grab all values from the connection box
// if one of them is missing then display an alert message
String ip = this.m_serverIP.getText().trim();
String port = this.m_serverPort.getText().trim();
if (ip.length() == 0) {
JOptionPane.showMessageDialog(null, "Please enter IP address !");
return;
}
if (port.length() == 0) {
JOptionPane.showMessageDialog(null, "Please enter Port number!");
return;
}
int s_port = 0;
try {
// try parse the Port number
// throws exception when an incorrect IP address
// is entered , and caught in the catch block
s_port = Integer.parseInt(port);
}
catch (Exception exp) {
JOptionPane.showMessageDialog(null, "Port number is incorrect!");
return;
}
try {
// try parse the IP address
// throws exception when an incorrect IP address
// is entered , and caught in the catch block
InetAddress.getByName(ip);
}
catch (Exception exp) {
JOptionPane.showMessageDialog(null, "IP address is incorrect!");
return;
}
m_frame.dispose();
this.m_ip = ip;
this.m_port = port;
setReady(true); //!!
// !! ready = true;
// new ServerGUI(ip , s_port);
}
}
// !! added
public void setReady(boolean ready) {
boolean oldValue = this.ready;
boolean newValue = ready;
this.ready = ready;
pcSupport.firePropertyChange(READY, oldValue, newValue);
}
//!! added
public void addPropertyChangeListener(PropertyChangeListener listener) {
pcSupport.addPropertyChangeListener(listener);
}
//!! added
public void removePropertyChangeListener(PropertyChangeListener listener) {
pcSupport.removePropertyChangeListener(listener);
}
public boolean isReady() {
return this.ready;
}
/**
*
* #return
*/
public String[] getIPandPort() {
String[] ipPort = new String[2];
ipPort[0] = this.m_ip;
ipPort[1] = this.m_port;
return ipPort;
}
}
I didn't realize until now that my disconnect button on my program was failing. If I have 3 clients up, and any of them click disconnect, then only the last client gets disconnected. How do I select which instance I need to close? If out of the 3 users I want to remove the first one..
server:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.HashSet;
import java.util.Scanner;
import java.util.Set;
public class Server {
private Set<Socket> sockets = new HashSet<Socket>();
private Set<String> names = new HashSet<String>();
private Socket sock;
private static int port;
private Calendar cal = Calendar.getInstance();
private SimpleDateFormat date = new SimpleDateFormat("dd/mm/yyyy hh:mm:ss");
public Server(int input) {
port = input;
}
public static void main(String[] args) {
/*
* user defines port number, server initialized
*/
System.out.println("enter a port");
Scanner input = new Scanner(System.in);
port = input.nextInt();
new Server(port).go();
input.close();
}
public void go() {
try {
/*
* wait for connections, add connections to Set, setup streams per
* connection in new threads
*/
System.out.println("waiting for connetion");
#SuppressWarnings("resource")
ServerSocket serverSocket = new ServerSocket(port);
while (true) {
sock = serverSocket.accept();
sockets.add(sock);
Thread t = new Thread(new ClientHandler(sock));
t.start();
System.out.println("connected: " + sock.getInetAddress());
}
} catch (IOException ex) {
ex.printStackTrace();
System.out.println("server setup failed");
}
}
class ClientHandler implements Runnable {
/*
* client handler sets up streams
*/
private BufferedReader in;
private PrintWriter out;
private String name;
public ClientHandler(Socket sock) {
try {
in = new BufferedReader(new InputStreamReader(
sock.getInputStream()));
out = new PrintWriter(sock.getOutputStream(), true);
} catch (IOException e) {
e.printStackTrace();
System.out.println("stream setup failed");
}
}
#Override
public void run() {
/*
* First check if user exists, if true than close connection and
* warn user about name. Then relay message to all clients, if user
* DC's than remove the socket from the Set
*/
String message;
try {
name = in.readLine();
if (names.contains(name)) {
System.out.println("duplicate name detected, removing..");
out.println("choose new name and reconnect: "
+ sock.getInetAddress());
sock.close();
sockets.remove(sock);
} else {
names.add(name);
System.out.println("Users active: " + names);
shout("user: " + name + " connected!" + " from "
+ sock.getInetAddress());
}
while ((message = in.readLine()) != null) {
/*
* call method which checks if user tries to enter a command
* such as /laugh or /roll, otherwise relay the message to
* all clients
*/
swich(message);
}
} catch (IOException ex) {
System.out.println("user disconnected: " + name + " "
+ sock.getInetAddress());
shout("user disconnected: " + name + " "
+ sock.getInetAddress());
names.remove(name);
remove(sock);
}
}
public synchronized void shout(String message) {
// send message to all clients in Set
for (Socket sock : sockets) {
try {
PrintWriter writer = new PrintWriter(
sock.getOutputStream(), true);
writer.println(date.format(cal.getTime()) + " " + message
+ "\n");
} catch (IOException e) {
e.printStackTrace();
}
}
}
public void swich(String message) throws IOException {
// check if user calls a chat command
// otherwise shout message to all clients
switch (message) {
case "/disconnect":
out.println("disconnected");
remove(sock);
break;
case "/laugh":
String[] laughs = { "HahHA!", "HAHAAH!!!!", "haaaaa!!!",
"hohohoohohahhaa!!!", "huehuehue!" };
shout(name + " " + laughs[(int) (Math.random() * 5)]);
break;
case "/roll":
shout(name + " rolls "
+ Integer.toString((int) ((Math.random() * 6) + 1)));
break;
case "kirby!":
shout("(>'-')> <('-'<) ^(' - ')^ <('-'<) (>'-')>");
break;
default:
shout(message);
System.out.println("client says : "
+ date.format(cal.getTime()) + message);
}
}
}
public void remove(Socket soc) {
try {
soc.close();
sockets.remove(soc);
} catch (IOException e) {
e.printStackTrace();
}
}
}
client:
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
public class Client {
private JTextArea tArea;
private JTextField tField;
private JTextField portText;
private JTextField hostText;
private BufferedReader in;
private Socket sock;
private static PrintWriter out;
private static String name;
private String host;
private String port;
public static void main(String[] args) {
System.out.println("Enter username");
Scanner input = new Scanner(System.in);
name = input.nextLine();
input.close();
new Client().go();
}
public void go() {
/*
* build gui
*/
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JFrame frame = new JFrame("hakobChat");
JPanel topPanel = new JPanel();
JLabel portLabel = new JLabel("port");
JLabel hostLabel = new JLabel("host");
portText = new JTextField(6);
hostText = new JTextField(12);
JButton connect = new JButton("connect");
connect.addActionListener(new connectListener());
JButton disconnect = new JButton("disconnect");
disconnect.addActionListener(new disconnectListener());
tField = new JTextField(30);
tField.addActionListener(new sendListener());
tArea = new JTextArea(30, 50);
tArea.setEditable(false);
tArea.setLineWrap(true);
JScrollPane tScroll = new JScrollPane(tArea,
JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
JButton button = new JButton("send");
button.addActionListener(new sendListener());
topPanel.add(hostLabel);
topPanel.add(hostText);
topPanel.add(portLabel);
topPanel.add(portText);
topPanel.add(connect);
topPanel.add(disconnect);
frame.setSize(300, 500);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(topPanel, BorderLayout.NORTH);
frame.getContentPane().add(tScroll, BorderLayout.CENTER);
frame.getContentPane().add(tField, BorderLayout.SOUTH);
frame.getContentPane().add(button, BorderLayout.EAST);
frame.pack();
}
});
}
public void setupNetwork(String host, int port) {
/*
* setup in and out stream send user name to server to check if
* duplicate start thread for incoming messages
*/
try {
sock = new Socket(host, port);
in = new BufferedReader(
new InputStreamReader(sock.getInputStream()));
out = new PrintWriter(sock.getOutputStream(), true);
out.println(name);
showMessage("Connected!");
showMessage("enter /laugh or /roll or kirby! for some fun!");
Thread t = new Thread(new IncomingReader());
t.start();
} catch (IOException ex) {
ex.printStackTrace();
showMessage("please enter valid network");
}
}
class IncomingReader implements Runnable {
// receive messages from server
public void run() {
try {
String message = null;
while ((message = in.readLine()) != null) {
showMessage(message + "\n");
}
} catch (Exception e) {
e.printStackTrace();
showMessage("choose new name and reconnect please");
}
}
}
public synchronized void sendMessage(String message) {
try {
switch (message) {
case "/laugh":
out.println("/laugh");
break;
case "/roll":
out.println("/roll");
break;
case "kirby!":
out.println("kirby!");
break;
default:
out.println("(" + name + ")" + ": " + message);
}
} catch (Exception e) {
e.printStackTrace();
System.out.println("fail send message");
}
}
public void showMessage(final String message) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
tArea.append(message + "\n");
tArea.setCaretPosition(tArea.getDocument().getLength());
// SetCaretPosition forces autos scroll
}
});
}
class sendListener implements ActionListener {
// listens for user to trying to send a message
public void actionPerformed(ActionEvent ev) {
sendMessage(tField.getText());
tField.setText("");
}
}
class disconnectListener implements ActionListener {
public void actionPerformed(ActionEvent ev) {
try {
out.println("/disconnect");
} catch (NullPointerException e) {
showMessage("not connected");
}
}
}
class connectListener implements ActionListener {
public void actionPerformed(ActionEvent ev) {
host = hostText.getText();
port = portText.getText();
if (!host.equals("") && !port.equals("") && port.matches("[1-9]+")) {
// make sure user enters valid inputs
// before setting up network
setupNetwork(host, Integer.parseInt(port));
} else {
showMessage("enter valid network credentials");
}
}
}
}
Also, how do I avoid this "#SuppressWarnings("resource")". If I don't have this eclipse provided warning than the serverSocket is underlined yellow.
You need to save a the Socket used for the client inside of the ClientHandler.
You can do this by simply adding a
private Socket sock;
inside of ClientHandler, and adding:
this.sock = sock;
inside of its constructor.
Currently you're using the Socket saved in the server, which will always be the socket of the last client that connected, rather than the Socket belonging to the current client.
This is just a scoping problem. The Socket sock member shouldn't be part of the Server class. It should be part of the ClientHandler class. One per client.
I'm working on the client side application of the client/server chat I'm doing for learning experience. My problem is I can't seem to get the socket and swing,both to run at the same time.
What I want to is, when the user opens a JOpionsPane and enters the hostname and port number, clicks okay, then they are connected. When the socket information was hardcoded it worked fine, but now I'm trying to get the users input for it.
What's meant to happen is, action listener is supposed to create the new SocketManager object that handles communication. Event though it says it's connected, it doesn't run. When I create the new SocketManager object and run it on a new thread it connects and revives messages form the server, but then the swings freezes and I have to end the process to shut it down.
Should I start it on a new worker thread or something? Maybe it's just because I'm tired, but I'm out of ideas.
EDIT
I updated my ActLis.class and SocketManager.class with the suggestion of adding a new thread for my SocketManager object 'network'. When I try and use 'network' though it returns null for some reason.
ActLis.clss
package com.client.core;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JTextField;
public class ActLis implements ActionListener {
private Main main = new Main();;
private JTextField ipadress = new JTextField(),
portnumber = new JTextField(),
actionField;
private String username;
final JComponent[] ipinp = new JComponent[]{new JLabel("Enter Hostname (IP Adress): "),
ipadress,
new JLabel("Enter Port number: "), portnumber};
private SocketManager network;
private Window win;
public ActLis(){
}
public ActLis(JTextField t, Window w){
actionField = t;
win = w;
}
#Override
public void actionPerformed(ActionEvent e) {
String cmd = e.getActionCommand();
if(cmd == "Exit"){
System.exit(0);
} else if(cmd == "Connect to IP"){
try{
JOptionPane.showMessageDialog(null, ipinp, "Connect to IP", JOptionPane.PLAIN_MESSAGE);
if(network != null){
network.close();
}
network = new SocketManager(ipadress.getText(),Integer.parseInt(portnumber.getText()));
network.setGUI(win);
Thread t = new Thread(network);
t.start();
JOptionPane.showMessageDialog(null, "Connected to chat host successfully!","Connected", JOptionPane.INFORMATION_MESSAGE);
}catch(Exception ee){
JOptionPane.showMessageDialog(null, "Could not connect. Check IP adress or internet connection","Error - Could not connect", JOptionPane.ERROR_MESSAGE);
ee.printStackTrace();
}
} else if (cmd == "chatWriter"){
if( actionField.getText() != ""){
try{
network.send(actionField.getText());
win.updateChat(actionField.getText());
actionField.setText("");
actionField.requestFocus();
}catch(Exception ex){
JOptionPane.showMessageDialog(null, "You are not connected to a host. (File -> Connect to IP)","Error - Not Connected", JOptionPane.ERROR_MESSAGE);
ex.printStackTrace();
}
}
} else if (cmd == "setUsername"){
username = actionField.getText();
network.send("USERNAME:" + username);
}
}
}
Main.class
package com.client.core;
import javax.swing.JFrame;
public class Main extends JFrame{
private SocketManager network;
public static void main(String[] args){
Main main = new Main();
main.run();
}
private void run(){
Window win = new Window();
win.setVisible(true);
}
}
SocketManager.class
package com.client.core;
import java.io.*;
import java.net.*;
public class SocketManager implements Runnable {
private Socket sock;
private PrintWriter output;
private BufferedReader input;
private String hostname;
private int portnumber;
private String message;
private Window gui;
public SocketManager(String ip, int port){
try{
hostname = ip;
portnumber = port;
}catch(Exception e){
System.out.println("Client: Socket failed to connect.");
}
}
public synchronized void send(String data){
try{
//System.out.println("Attempting to send: " + data);
output.println(data);
output.flush();
//System.out.println("Message sent.");
}catch(Exception e){
System.out.println("Message could not send.");
}
}
public synchronized void setGUI(Window w){
gui = w;
}
public synchronized void connect(){
try{
sock = new Socket(hostname,portnumber);
}catch(Exception e){
}
}
public synchronized Socket getSocket(){
return sock;
}
public synchronized void setSocket(SocketManager s){
sock = s.getSocket();
}
public synchronized void close(){
try{
sock.close();
}catch(Exception e){
System.out.println("Could not close connection.");
}
output = null;
input = null;
System.gc();
}
public synchronized boolean isConnected(){
return (sock == null) ? false : (sock.isConnected() && !sock.isClosed());
}
public synchronized void listenStream(){
try {
while((message = input.readLine()) != null){
System.out.println("Server: " + message);
gui.updateChat(message);
}
} catch (Exception e) {
}
}
#Override
public void run() {
try {
sock = new Socket(hostname,portnumber);
output = new PrintWriter(sock.getOutputStream(),true);
input = new BufferedReader(
new InputStreamReader(sock.getInputStream()));
while(true){
listenStream();
}
} catch (Exception e) {
System.out.println("Run method fail. -> SocketManager.run()");
}finally{
try {
sock.close();
} catch (Exception e) {
}
}
}
}
Window.class
package com.client.core;
import java.awt.*;
import javax.swing.*;
public class Window extends JFrame{
private int screenWidth = 800;
private int screenHeight = 600;
private SocketManager network;
private JPanel window = new JPanel(new BorderLayout()),
center = new JPanel(new BorderLayout()),
right = new JPanel(new BorderLayout()),
display = new JPanel( new BorderLayout()),
chat = new JPanel(),
users = new JPanel(new BorderLayout());
private JTextArea chatBox = new JTextArea("Welcome to the chat!", 7,50),
listOfUsers = new JTextArea("None Online");
private JTextField chatWrite = new JTextField(),
userSearch = new JTextField(10),
username = new JTextField();
private JScrollPane userList = new JScrollPane(listOfUsers),
currentChat = new JScrollPane(chatBox);
private JMenuBar menu = new JMenuBar();
private JMenu file = new JMenu("File");
private JMenuItem exit = new JMenuItem("Exit"),
ipconnect = new JMenuItem("Connect to IP");
private JComponent[] login = new JComponent[]{new JLabel("Username:"), username};
public Window(){
//Initial Setup
super("NAMEHERE - Chat Client Alpha v0.0.1");
setResizable(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(screenWidth,screenHeight);
//Panels
listOfUsers.setLineWrap(true);
listOfUsers.setEditable(false);
display.setBackground(Color.black);
chat.setLayout(new BoxLayout(chat, BoxLayout.Y_AXIS));
chat.setBackground(Color.blue);
users.setBackground(Color.green);
//TextFields
addChatArea();
//Menu bar
addMenuBar();
//Adding the main panels.
addPanels();
//Listeners
addListeners();
for(int x = 0; x < 1; x++){
login();
}
}
private void login(){
JOptionPane.showMessageDialog(null, login, "Log in", JOptionPane.PLAIN_MESSAGE);
}
private void addChatArea(){
chatBox.setEditable(false);
userList.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
currentChat.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
users.add(userList);
users.add(userSearch, BorderLayout.NORTH);
chat.add(currentChat);
chat.add(chatWrite);
chat.setBorder(BorderFactory.createEmptyBorder(1, 1, 1, 1));
}
private void addMenuBar(){
file.add(ipconnect);
file.add(exit);
menu.add(file);
}
private void addPanels(){
right.add(users);
center.add(display, BorderLayout.CENTER);
center.add(chat, BorderLayout.SOUTH);
window.add(center, BorderLayout.CENTER);
window.add(right, BorderLayout.EAST);
window.add(menu, BorderLayout.NORTH);
add(window);
}
private void addListeners(){
username.addActionListener(new ActLis(username, this));
chatWrite.addActionListener(new ActLis(chatWrite, this));
username.setActionCommand("setUsername");
chatWrite.setActionCommand("chatWriter");
ipconnect.addActionListener(new ActLis());
exit.addActionListener(new ActLis());
}
public void setNetwork(SocketManager n){
network = n;
}
public void updateChat(String s){
chatBox.setText(chatBox.getText() + "\n" + s);
}
}
Ok #Zexanima you have create a Socket class for socket manager. Something like this:
public class YouSocketClass {
static public Socket socket = null;
static public InputStream in = null;
static public OutputStream out = null;
public YouSocketClass() {
super();
}
public static final Socket getConnection(final String ip, final int port, final int timeout) {
try {
socket = new Socket(ip, port);
try {
socket.setSoTimeout(timeout);
} catch(SocketException se) {
log("Server Timeout");
}
in = socket.getInputStream();
out = socket.getOutputStream();
} catch(ConnectException e) {
log("Server name or server ip is failed. " + e.getMessage());
e.printStackTrace();
} catch(Exception e) {
log("ERROR Socket: " + e.getMessage() + " " + e.getCause());
e.printStackTrace();
}
return socket;
}
public static void closeConnection() {
try {
if(socket != null) {
if(in != null) {
if(out != null) {
socket.close();
in.close();
out.close();
}
}
}
} catch(Exception e2) {
e2.printStackTrace();
}
}
private static Object log(Object sms) {
System.out.println("Test Socket1.0: " + sms);
return sms;
}
}
I hope that serve. :)