Display online users from server to all connected clients - java

I'm building simple socket server-client application consisting of:
Server project (which creates new client handler thread when socket is accepted) and a Client project (which establishing connection with the server and displaying gui with message thread open).
So far I'm able to connect using multiple clients and chat with no problems.
I've set a command called !getusers that should display all connected users to the requesting client.
When I do so, I'm suddenly unable to continue and chat, the client simply get stuck, I do get the connected users list though.
As for a request here is the entire client code:
import java.io.*;
import java.net.*;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import static java.lang.System.out;
import java.util.logging.Level;
import java.util.logging.Logger;
public class ChatClient extends JFrame implements ActionListener {
String uname;
PrintWriter pw;
BufferedReader br;
JTextArea taMessages, taUserList;
JTextField tfInput;
JButton btnSend, btnExit;
Socket client;
public ChatClient(String uname, String servername) throws Exception {
super("Connected as: " + uname); // set title for frame
this.uname = uname;
client = new Socket(servername, 18524);
br = new BufferedReader(new InputStreamReader(client.getInputStream()));
pw = new PrintWriter(client.getOutputStream(), true);
pw.println(uname); // send name to server
//bring up the chat interface
buildInterface();
new MessagesThread().start(); // create thread that listens for messages
}
public void buildInterface() {
btnSend = new JButton("Send");
btnExit = new JButton("Exit");
//chat area
taMessages = new JTextArea();
taMessages.setRows(10);
taMessages.setColumns(50);
taMessages.setEditable(false);
//online users list
taUserList = new JTextArea();
taUserList.setRows(10);
taUserList.setColumns(10);
taUserList.setEditable(false);
//top panel (chat area and online users list
JScrollPane chatPanel = new JScrollPane(taMessages, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
JScrollPane onlineUsersPanel = new JScrollPane(taUserList, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
JPanel tp = new JPanel(new FlowLayout());
tp.add(chatPanel);
tp.add(onlineUsersPanel);
add(tp, "Center");
//user input field
tfInput = new JTextField(50);
//buttom panel (input field, send and exit)
JPanel bp = new JPanel(new FlowLayout());
bp.add(tfInput);
bp.add(btnSend);
bp.add(btnExit);
add(bp, "South");
btnSend.addActionListener(this);
tfInput.addActionListener(this);//allow user to press Enter key in order to send message
btnExit.addActionListener(this);
setSize(500, 300);
setVisible(true);
pack();
}
#Override
public void actionPerformed(ActionEvent evt) {
if (evt.getSource() == btnExit) {
pw.println("!end"); // send end to server so that server know about the termination
System.exit(0);
} else if(tfInput.getText().contains("!getusers")){
pw.println("!getusers");
}else{
// send message to server
pw.println(tfInput.getText());
}
}
public static void main(String args[]) {
// take username from user
String name = JOptionPane.showInputDialog(null, "Enter your name: ", "Username",
JOptionPane.PLAIN_MESSAGE);
String servername = "localhost";
try {
new ChatClient(name, servername);
} catch (Exception ex) {
out.println("Unable to connect to server.\nError: " + ex.getMessage());
}
} // end of main
// inner class for Messages Thread
class MessagesThread extends Thread {
#Override
public void run() {
String line;
try {
while (true) {
line = br.readLine();
taMessages.append(line + "\n");
taMessages.setCaretPosition(taMessages.getDocument().getLength());//auto scroll to last message
} // end of while
} catch (Exception ex) {
}
}
}
} // end of client
Which then accepted and handled by the server, following is the entire server code:
public class ChatServer {
Vector<String> users = new Vector<String>();
Vector<HandleClient> clients = new Vector<HandleClient>();
public void process() throws Exception {
ServerSocket server = new ServerSocket(18524);
out.println("Server Started...");
while (true) {
Socket client = server.accept();
//add incoming client to connected clients vector.
HandleClient c = new HandleClient(client);
clients.add(c);
} // end of while
}
public static void main(String... args) throws Exception {
new ChatServer().process();
} // end of main
public void broadcast(String user, String message) {
// send message to all connected users
for (HandleClient c : clients) {
c.sendMessage(user, message);
}
}
/*
* Inner class, responsible of handling incoming clients.
* Each connected client will set as it's own thread.
*/
class HandleClient extends Thread {
String name = "";//client name/username
BufferedReader input;//get input from client
PrintWriter output;//send output to client
public HandleClient(Socket client) throws Exception {
// get input and output streams
input = new BufferedReader(new InputStreamReader(client.getInputStream()));
output = new PrintWriter(client.getOutputStream(), true);
// read name
name = input.readLine();
users.add(name); // add to users vector
broadcast(name, " Has connected!");
start();
}
public void sendMessage(String uname, String msg) {
output.println(uname + ": " + msg);
}
public void getOnlineUsers() {
for (HandleClient c : clients) {
for (int i = 0; i < users.size(); i++) {
broadcast("", users.get(i));
}
}
}
public String getUserName() {
return name;
}
public void run() {
String line;
try {
while (true) {
line = input.readLine();
if (line.equals("!end")) {
//notify all for user disconnection
broadcast(name, " Has disconnected!");
clients.remove(this);
users.remove(name);
break;
} else if(line.equals("!getusers")){
getOnlineUsers();
break;
}
broadcast(name, line); // method of outer class - send messages to all
} // end of while
} // try
catch (Exception ex) {
System.out.println(ex.getMessage());
}
} // end of run()
} // end of inner class
} // end of Server
Should I defince a new PrintWriter object for handling the onlineUsers request?
I'm sure I'm missing something here, but yet to figure out what exactly.

Ah, I have solved the puzzle.
public void run() {
String line;
try {
while (true) {
line = input.readLine();
if (line.equals("!end")) {
// Blah
} else if(line.equals("!getusers")){
getOnlineUsers();
break; << This breaks your read loop
}
broadcast(name, line); // method of outer class - send messages to all
} // end of while
} // try
catch (Exception ex) {
System.out.println(ex.getMessage());
}
} // end of run()
The break statement in your run() loop terminates your reading loop, so the server is no longer "listening" to your client. I believe if you remove the break, it should be all good.

Related

Running a .java file and instantiating the class contained in it give me different results

I have a Java program that is using threads to transfer data through sockets. The issue I am having is in my server manager when I create a thread pool. If for instance I create a thread-pool of 3, waiting for 3 clients to connect, and then manually run CapitalizeClient.java 3 times, everything works fine and I can manage threads/close sockets perfectly fine, but if I create that same thread-pool and then automate the creating of CapitalizeClient.java by instantiating the class within a loop, I run into a huge issue, being that when I go to close a socket every socket in my entire program closes and everything shuts down.
Here is the class that's giving me trouble
package parallel_hw_6;
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.Timer;
import java.util.TimerTask;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
public class CapitalizeClient {
private BufferedReader in;
private PrintWriter out;
private JFrame frame = new JFrame("Capitalize Client");
private JTextField dataField = new JTextField(40);
private JTextArea messageArea = new JTextArea(8, 60);
private String name;
private JTextArea log = new JTextArea(20,20);
/**
* Constructs the client by laying out the GUI and registering a
* listener with the textfield so that pressing Enter in the
* listener sends the textfield contents to the server.
*/
public CapitalizeClient() {
// Layout GUI
messageArea.setEditable(false);
frame.getContentPane().add(dataField, "North");
frame.getContentPane().add(new JScrollPane(messageArea), "Center");
frame.getContentPane().add(new JScrollPane(log), "East");
// Add Listeners
dataField.addActionListener(new ActionListener() {
/**
* Responds to pressing the enter key in the textfield
* by sending the contents of the text field to the
* server and displaying the response from the server
* in the text area. If the response is "." we exit
* the whole application, which closes all sockets,
* streams and windows.
*/
public void actionPerformed(ActionEvent e) {
out.println(dataField.getText());
}
});
}
/**
* Implements the connection logic by prompting the end user for
* the server's IP address, connecting, setting up streams, and
* consuming the welcome messages from the server. The Capitalizer
* protocol says that the server sends three lines of text to the
* client immediately after establishing a connection.
*/
public void connectToServer() throws IOException {
// Get the server address from a dialog box.
String serverAddress = JOptionPane.showInputDialog(
frame,
"Enter IP Address of the Server:",
"Welcome to the Capitalization Program",
JOptionPane.QUESTION_MESSAGE);
// Make connection and initialize streams
Socket socket = new Socket(serverAddress, 9898);
in = new BufferedReader(
new InputStreamReader(socket.getInputStream()));
out = new PrintWriter(socket.getOutputStream(), true);
// Consume the initial welcoming messages from the server
for (int i = 0; i < 3; i++) {
messageArea.append(in.readLine() + "\n");
System.out.println("initial message: "+i);
}
name = in.readLine();
Timer timer = new Timer();
TimerTask serverHeartbeat = new TimerTask() {
#Override
public void run() {
out.println(name+"_IS_ALIVE");
}
};
TimerTask threadHeartbeat = new TimerTask() {
#Override
public void run() {
out.println(name+"_ALIVE");
}
};
timer.schedule(serverHeartbeat, 1000, 1000);
timer.schedule(threadHeartbeat, 5000, 5000);
String response;
try {
while((response = in.readLine()) != null){
System.out.println("The input is: " + response);
Matcher m2 = Pattern.compile("([\\w]*)_ALIVE").matcher(response);
if (response == null || response.equals("")) {
System.exit(0);
}else if("CLEAR_CONSOLE".equals(response)){
messageArea.setText(null);
}else if(m2.matches()){
log.append(response+"\n");
}else{
messageArea.append(response + "\n");
dataField.selectAll();
}
}
if (response == null || response.equals("")) {
System.exit(0);
}
} catch (IOException ex) {
response = "Error: " + ex;
}
}
/**
* Runs the client application.
*/
public static void main(String[] args) throws Exception {
CapitalizeClient client = new CapitalizeClient();
client.frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
client.frame.pack();
client.frame.setVisible(true);
client.connectToServer();
}
}
Here is how I'm trying to instantiate n = thread-pool-size instances of the class to connect
for(int i = 0; i < numClients; i++){
(new Thread() {
#Override
public void run() {
try {
CapitalizeClient.main(null);
} catch (Exception ex) {
Logger.getLogger(CapitalizeServer.class.getName()).log(Level.SEVERE, null, ex);
}
}
}).start();
}
Note: When I instantiate multiple instances of the class this way they DO show up and connect properly as well as allow me to send messages to all of them or even to specific ones, it's just that when I go to close the socket down, ending the connection to one of the clients, it shuts all the clients down and then the server manager.
Here is a copy of the server manager code for reference.
package parallel_hw_6;
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.util.ArrayList;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class CapitalizeServer {
private static ArrayList<Capitalizer> allClients = new ArrayList<Capitalizer>();
private static ServerSocket listener;
private static ServerSocket listener2;
private static ExecutorService pool = Executors.newCachedThreadPool();
private static int threadPoolNum = 0;
private static Settings s;
private static RunIt runIt;
/**
* Application method to run the server runs in an infinite loop listening
* on port 9898. When a connection is requested, it spawns a new thread to
* do the servicing and immediately returns to listening. The server keeps a
* unique client number for each client that connects just to show
* interesting logging messages. It is certainly not necessary to do this.
*/
public static void main(String[] args) throws Exception {
System.out.println("The capitalization server is running.");
int clientNumber = 0;
int settingsClientNumber = 0;
listener = new ServerSocket(9898);
listener2 = new ServerSocket(9899);
// new Settings(listener2.accept(), settingsClientNumber++).start();
s = new Settings(listener2.accept(), settingsClientNumber++);
s.start();
// threadPool(2);
runIt = new RunIt();
try {
while (true) {
// new Capitalizer(listener.accept(), clientNumber++).start();
Capitalizer c = new Capitalizer(listener.accept(), clientNumber++, false, s);
Thread t = new Thread(c);
t.start();
}
} finally {
listener.close();
}
}
/**
* A private thread to handle capitalization requests on a particular
* socket. The client terminates the dialogue by sending a single line
* containing only a period.
*/
private static class Capitalizer implements Runnable {
private Socket socket;
private int clientNumber;
private String name;
private BufferedReader in;
private PrintWriter out;
private boolean fromThreadPool;
private Settings admin;
// private PrintWriter adminOut;
public Capitalizer(Socket socket, int clientNumber, boolean fromWhere, Settings admin) {
this.admin = admin;
// this.setName("Thread" + clientNumber);
this.fromThreadPool = fromWhere;
if (this.fromThreadPool == true) {
this.name = "Threadpool_Thread_" + clientNumber;
} else {
this.name = "Standard_Thread_" + clientNumber;
}
this.socket = socket;
this.clientNumber = clientNumber;
log("\nNew connection with client# " + clientNumber + " at " + socket);
allClients.add(this);
System.out.print("\n" + allClients);
try {
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
out = new PrintWriter(socket.getOutputStream(), true);
// adminOut = new PrintWriter(adminSocket.getOutputStream(), true);
} catch (Exception e) {
}
}
/**
* Services this thread's client by first sending the client a welcome
* message then repeatedly reading strings and sending back the
* capitalized version of the string.
*/
public void run() {
try {
// Decorate the streams so we can send characters
// and not just bytes. Ensure output is flushed
// after every newline.
// Send a welcome message to the client.
out.println("Hello, your name is " + name + ".");
out.println("Enter a line with only a period to quit\n");
out.println(name);
// Get messages from the client, line by line; return them
// capitalized
while (true) {
String input = in.readLine();
// System.out.println("\nInput check: "+ input);
Matcher m = Pattern.compile("([\\w]*)_IS_ALIVE").matcher(input);
Matcher m2 = Pattern.compile("([\\w]*)_ALIVE").matcher(input);
if (input == null || input.equals(".")) {
break;
} else if (m.matches()) {
admin.showHeartbeat(input);
} else if (m2.matches()) {
heartbeatToAll(input, this.name);
} else {
out.println(input.toUpperCase());
}
// out.println(input.toUpperCase());
}
} catch (IOException e) {
log("Error handling client# " + clientNumber + ": " + e);
} finally {
try {
socket.close();
} catch (IOException e) {
log("Couldn't close a socket, what's going on?");
}
log("Connection with client# " + clientNumber + " closed");
}
}
private void sendMessage(String message) {
try {
out.println(message);
} catch (Exception e) {
log("Error: Message could not be sent");
}
}
private void terminate() {
try {
socket.close();
} catch (Exception e) {
log("Couldn't close a socket, what's going on?");
}
}
/**
* Logs a simple message. In this case we just write the message to the
* server applications standard output.
*/
private void log(String message) {
System.out.println(message);
}
}
private static void threadPool(int numClients) {
try {
Thread waitForConnection = new Thread() {
#Override
public void run() {
try {
for (int i = 0; i < numClients; i++) {
System.out.print("Threadpool" + pool);
Capitalizer c = new Capitalizer(listener.accept(), threadPoolNum++, true, s);
pool.execute(c);
}
} catch (IOException ex) {
Logger.getLogger(CapitalizeServer.class.getName()).log(Level.SEVERE, null, ex);
}
}
};
waitForConnection.start();
System.out.println("\nInside threadPool() - Number of threads in pool is " + numClients);
// Works but closes all if you close one
for (int i = 0; i < numClients; i++) {
(new Thread() {
#Override
public void run() {
try {
CapitalizeClient.main(null);
// CapitalizeClient test = new CapitalizeClient();
// test.main(null);
} catch (Exception ex) {
Logger.getLogger(CapitalizeServer.class.getName()).log(Level.SEVERE, null, ex);
}
}
}).start();
}
} catch (Exception ex) {
Logger.getLogger(CapitalizeServer.class.getName()).log(Level.SEVERE, null, ex);
}
}
private static void heartbeatToAll(String message, String name) {
String m = message;
String n = name;
for (int i = 0; i < allClients.size(); i++) {
String cName = allClients.get(i).name;
if (!cName.equals(n)) {
allClients.get(i).sendMessage(message);
}
}
}
private static class Settings extends Thread {
private Socket socket;
private int clientNumber;
private static PrintWriter out;
public Settings(Socket socket, int clientNumber) {
this.socket = socket;
this.clientNumber = clientNumber;
log("\nNew connection with settings client# " + clientNumber + " at " + socket);
}
/**
* Services this thread's client by first sending the client a welcome
* message then repeatedly reading strings and sending back the
* capitalized version of the string.
*/
public void run() {
try {
// Decorate the streams so we can send characters
// and not just bytes. Ensure output is flushed
// after every newline.
BufferedReader in = new BufferedReader(
new InputStreamReader(socket.getInputStream()));
out = new PrintWriter(socket.getOutputStream(), true);
// Send a welcome message to the client.
out.println("Hello, you are admin client #" + clientNumber + ".");
out.println("Enter a line with only a period to quit\n");
// Get messages from the client, line by line; return them
// capitalized
while (true) {
String input = in.readLine();
int intInput = 0;
Matcher m = Pattern.compile("([\\w]*)_IS_ALIVE").matcher(input);
if (input == null || input.equals(".")) {
break;
} else if (m.matches()) {
out.println(input);
break;
} else {
try {
intInput = Integer.parseInt(input);
System.out.print("\nintInput: " + intInput);
switch (intInput) {
case (1):
out.println("Which thread should I terminate?");
for (int i = 0; i < allClients.size(); i++) {
String toAdd = i + " : " + allClients.get(i).name;
out.println(toAdd);
}
while (true) {
String choice1 = in.readLine();
try {
int intChoice1 = Integer.parseInt(choice1);
System.out.print("\nintChoice1: " + intChoice1);
allClients.get(intChoice1).terminate();
out.println("CLEAR_CONSOLE");
out.println("Client number " + intChoice1 + " has been terminated");
if (allClients.get(intChoice1).fromThreadPool == true) {
threadPool(1);
}
allClients.remove(intChoice1);
System.out.println("\nall clients: " + allClients);
break;
} catch (Exception e) {
out.println("Enter a valid client number.");
log(e.toString());
}
}
break;
case (2):
out.println("Send to one or all?");
out.println("1. Choose 1");
out.println("2. Send to all");
while (true) {
String allOrOne = in.readLine();
try {
int intAllOrOne = Integer.parseInt(allOrOne);
System.out.print("\nintAllOrOne: " + intAllOrOne);
switch (intAllOrOne) {
case (1):
out.println("CLEAR_CONSOLE");
out.println("Which do you want to send to?");
for (int i = 0; i < allClients.size(); i++) {
String toAdd = Integer.toString(allClients.get(i).clientNumber);
String toPrint = i + " : " + allClients.get(i).name;
out.println(toPrint);
}
while (true) {
String sendToWho = in.readLine();
try {
int intSendToWho = Integer.parseInt(sendToWho);
System.out.print("\nintsendToWho: " + intSendToWho);
out.println("CLEAR_CONSOLE");
out.println("Enter message to send.");
while (true) {
String message = in.readLine();
System.out.print("\nmessage: " + message);
try {
allClients.get(intSendToWho).sendMessage(message);
break;
} catch (Exception e) {
out.print("Enter a valid client number.");
log(e.toString());
}
}
out.println("CLEAR_CONSOLE");
break;
} catch (Exception e) {
out.println("Enter a valid choice.");
log(e.toString());
}
}
break;
case (2):
out.println("CLEAR_CONSOLE");
out.println("Enter message to send test.");
while (true) {
String message = in.readLine();
System.out.print("\nmessage: " + message);
try {
for (int i = 0; i < allClients.size(); i++) {
allClients.get(i).sendMessage(message);
}
out.println("CLEAR_CONSOLE");
break;
} catch (Exception e) {
out.print("Enter a valid client number.");
log(e.toString());
}
}
break;
}
break;
} catch (Exception e) {
log(e.toString());
}
}
break;
case (3):
out.println("How many threads in the pool?");
while (true) {
String numThreads = in.readLine();
try {
int intNumThreads = Integer.parseInt(numThreads);
System.out.print("\nintNumThreads: " + intNumThreads);
out.println("CLEAR_CONSOLE");
out.println("Thread pool with" + intNumThreads + " has been created!");
out.println("Spawn new instance(s) of 'CapitalizeClient' class to utilize it.");
threadPool(intNumThreads);
break;
} catch (Exception e) {
out.println("Enter a valid number.");
log(e.toString());
}
}
break;
default:
out.println("Please enter a valid option.");
break;
}
} catch (Exception e) {
System.out.print("\nnumber format exception\n");
out.println("Please enter a valid option.");
}
}
}
} catch (IOException e) {
log("Error handling client# " + clientNumber + ": " + e);
} finally {
System.out.print("FINALLY IS EXECUTING!");
try {
socket.close();
} catch (IOException e) {
log("Couldn't close a socket, what's going on?");
}
log("Here?Connection with client# " + clientNumber + " closed");
}
}
private static void showHeartbeat(String h) {
out.println(h);
}
/**
* Logs a simple message. In this case we just write the message to the
* server applications standard output.
*/
private void log(String message) {
System.out.println(message);
}
}
}

Instance variable String in Outer Class being set to null before Inner Class can use it

I'm working on a project to implement the game "Monopoly" in Java. I've currently setup a GUI on top of my client code to take text input to a chat box (or to send commands) to the server.
My Controller.java class is the code to start the GUI. When a user enters the IP and port of the game server and hits submit, the server listening to that Socket then instantiates a thread of the Controller.java inner class ClientServiceThread. This class is what should send messages between the GUI - Client - Server.
My problem is that in the outer class (Controller.java) I have an instance variable called "messageText". Later on when a user enters a message to the Chatbox, I assign that text to the "messageText" variable. However, when I attempt to grab that variable in the ClientServiceThread, it is always null. I believe this is because the server created both a new client and a new controller, which would mean the variable I'm trying to get hasn't actually been modified.
Server Code Snippet
public void run() {
try {
myServerSocket = new ServerSocket(8888);
} catch(IOException ioe) {
System.out.println("Could not create server socket on port 8888. Quitting.");
System.exit(-1);
}
System.out.println("Server successfully started");
while(ServerOn) {
try {
Socket clientSocket = myServerSocket.accept();
Controller.ClientServiceThread cliThread = new Controller().new ClientServiceThread(clientSocket, clientidnum);
cliThread.start();
//adds clients to array in order they join
connectedClients[clientidnum] = cliThread;
//increments connected ID client var
clientidnum++;
} catch(IOException ioe) {
System.out.println("Exception found on accept. Ignoring. Stack Trace :");
ioe.printStackTrace();
}
}
Controller.java Code Snippet
public class Controller extends Application implements Initializable {
Socket myClientSocket;
boolean m_bRunThread = true;
String hostname;
int hostportnumber;
private ObservableList<String> chatMessages = FXCollections.observableArrayList();
String messageText = "";
private void handleChatAction(ActionEvent event) throws IOException {
if (event.getSource() == sendchatButton){
String chat = chatInput.getText();
if(chat != null && !chat.trim().isEmpty()) {
chatMessages.add(chat);
messageText = chat;
chatmessagesList.setItems(chatMessages);
chatmessagesList.scrollTo(chatMessages.size());
}
chatInput.clear();
}
}
Inner Class ClientServiceThread Snippet
class ClientServiceThread extends Thread {
Socket myClientSocket;
boolean m_bRunThread = true;
String hostname;
int hostportnumber;
int id;
public ClientServiceThread() {
super();
}
ClientServiceThread(Socket s, int clientid) {
myClientSocket = s;
id = clientid;
}
public String getTextField(){
if(Controller.this.messageText != "") {
return Controller.this.messageText;
}
else {
return "";
}
}
public void run() {
BufferedReader in = null;
PrintWriter out = null;
System.out.println("Accepted Client Address - " + myClientSocket.getInetAddress().getHostName());
try {
in = new BufferedReader(new InputStreamReader(myClientSocket.getInputStream()));
out = new PrintWriter(new OutputStreamWriter(myClientSocket.getOutputStream()));
while(m_bRunThread) {
String clientCommand = getTextField();
System.out.println("Client Says :" + clientCommand);
I apologize for the huge walls of code. I've taken out hundreds of lines of code just to reduce the amount you need to sift through. This bug is really hindering me and I can't progress to develop the actual game unless the client can communicate with the server.
Here are links to a gist of the full files of code if you wish to have a look at them. Thanks!
https://gist.github.com/anonymous/0961189791b8127598b3b3d7ca527987

Socket is not sending/receiving over multi-threaded java program

I'm creating a chat for a game that runs on a server and client system, and then of course the game on the server client system, but I cannot get my multithreaded program to work, and I'll explain how below. What I can say is the server client system works when single threaded.
To start, my connection class:
public class Connection {
private Server server;
private Client client;
private boolean serverChosen;
public Connection(){
server = new Server();
this.serverChosen = true;
}
public Connection(String IP){
client = new Client(IP);
this.serverChosen = false;
}
public synchronized void sendObjects(Object obj) throws IOException{
if(serverChosen){
server.sendObjects(obj);
}else{
client.sendObjects(obj);
}
}
public synchronized Object receiveObjects() throws ClassNotFoundException, IOException{
if(serverChosen){
return server.receiveObjects();
}else{
return client.receiveObjects();
}
}
public Object waitForObject() throws ClassNotFoundException, IOException{
int i = 0;
Object obj;
while(true){
obj = receiveObjects();
i++;
if(obj != null || i >= 100){
return obj;
}
}
}
}
Server and Client classes:
public class Server implements Serializable{
private ObjectOutputStream output;
private ObjectInputStream input;
private ServerSocket server;
private Socket connection;
//constructor
public Server(){
try{
server = new ServerSocket(8790, 10); //8798 is a dummy port for testing, this can be changed. The 100 is the maximum people waiting to connect.
try{
//Trying to connect and have conversation
waitForConnection();
setupStreams();
}catch(EOFException eofException){
}
} catch (IOException ioException){
ioException.printStackTrace();
}
}
//wait for connection, then display connection information
private void waitForConnection() throws IOException{
connection = server.accept();
}
//get stream to send and receive data
private void setupStreams() throws IOException{
output = new ObjectOutputStream(connection.getOutputStream());
output.flush();
input = new ObjectInputStream(connection.getInputStream());
}
public ObjectOutputStream getOutput(){
return output;
}
public ObjectInputStream getInput(){
return input;
}
public void sendObjects(Object obj) throws IOException{
output.writeObject(obj);
output.flush();
}
public Object receiveObjects() throws IOException, ClassNotFoundException{
return input.readObject();
}
}
public class Client extends JFrame implements Serializable{
private static final long serialVersionUID = 1L;
private ObjectOutputStream output;
private ObjectInputStream input;
private String serverIP;
private Socket connection;
private boolean next = true;
//constructor
public Client(String host){
serverIP = host;
try{
connectToServer();
setupStreams();
}catch(EOFException eofException){
}catch(IOException ioException){
ioException.printStackTrace();
}
}
public Client(){
serverIP = "127.0.0.1";
try{
connectToServer();
if(next){
setupStreams();
}
}catch(EOFException eofException){
//t.append("Connection was terminated");
}catch(IOException ioException){
ioException.printStackTrace();
}
}
//connect to server
private void connectToServer(){
int i = 0;
do {
try {
connection = new Socket(InetAddress.getByName(serverIP), 8790);
next = true;
} catch (IOException e) {
e.printStackTrace();
JOptionPane.showMessageDialog(null, "Server was not found, The program will try again in 1 second; number of tries left: " + (10-i));
next = false;
try {
Thread.sleep(1000);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
i++;
}
}while(!next && i<=10);
if(!next){
JOptionPane.showMessageDialog(null, "Unable to connect to the server. Make sure the I.P. adress is correct, the ports are not blocked, or a firewall has not prevented connections.... IDK man... it's just me and all of this code... maybe the server isn't even running??");
}
}
//set up streams
private void setupStreams() throws IOException{
output = new ObjectOutputStream(connection.getOutputStream());
output.flush();
input = new ObjectInputStream(connection.getInputStream());
}
public ObjectOutputStream getOutput(){
return output;
}
public ObjectInputStream getInput(){
return input;
}
public void sendObjects(Object obj) throws IOException{
output.writeObject(obj);
output.flush();
}
public Object receiveObjects() throws ClassNotFoundException, IOException{
return input.readObject();
}
}
The class I'm running everything on is the Frame class:
public class Frame implements ActionListener{
private int width;
private int height;
private JFrame jframe;
private Board board;
private JTextArea textBox;
private JScrollPane pane;
private Connection connection;
private JTextArea userText;
private JScrollPane userPane;
private JButton send;
private NetworkReceiver net;
public Frame(int width, int height, Connection connection, Board player, Board opponent){
this.width = width;
this.height = height;
this.connection = connection;
board = new Board(player, opponent);
init();
textBox = new JTextArea("CHAT WINDOW");
textBox.setWrapStyleWord(true);
textBox.setLineWrap(true);
textBox.setBackground(Color.GRAY);
textBox.setBounds(height, 0, width - (height) - 20, height-40);
textBox.setEditable(false);
userText = new JTextArea("Enter Messages Here");
userText.setWrapStyleWord(true);
userText.setLineWrap(true);
userText.setBackground(Color.WHITE);
userText.setBounds(height, height-40, width - (height) - 20, 40);
pane = new JScrollPane(textBox,
ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
pane.setBounds(height, 0, width - (height), height-40);
userPane = new JScrollPane(userText,
ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
userPane.setBounds(height, height-40, width - (height) - 20, 40);
send = new JButton();
send.setIcon(Utility.getImageIcon(Utility.getBufferedImage(Assets.send)));
send.setBounds(width - 20, height - 40, 20, 40);
send.addActionListener(this);
send.setBackground(Color.WHITE);
jframe = new JFrame();
jframe.setBackground(Color.DARK_GRAY);
jframe.getContentPane().setPreferredSize(new Dimension(width, height));
jframe.setLayout(null);
jframe.pack();
jframe.setLocationRelativeTo(null);
jframe.add(pane);
jframe.add(userPane);
jframe.add(send);
for(Space[] s: board.getSpaces()){
for(Space space: s){
jframe.add(space);
}
}
for(Space[] s: board.getSpaces()){
for(Space space: s){
space.addActionListener(this);
}
}
for(Space[] s: board.getSpaces()){
for(Space space: s){
if(space.getTile() != null){
space.setBackground(space.getTile().getColor());
}
}
}
for(Space[] s: board.getSpaces()){
for(Space space: s){
if(space.getPiece() != null){
space.setIcon(Utility.getImageIcon(space.getPiece().getImage()));
}
}
}
jframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jframe.setVisible(true);
net = new NetworkReceiver(connection, this);
net.start();
}
private void init(){
//stuff
}
#Override
public void actionPerformed(ActionEvent e) {
if(e.getSource() == send){
send();
}
}
private synchronized void send() {
String message = "YOU- " + userText.getText();
userText.setText("");
String totalMessage = textBox.getText();
textBox.setText(totalMessage + "\n" + message);
new NetworkSender(connection, message).start();
}
public synchronized void showMessage(String s){
String totalMessage = "Opponent- " + textBox.getText();
textBox.setText(totalMessage + "\n" + s);
}
I do not want to delete anything more in the constructor above in case it is in some way causing the issue(which I doubt but since I cannot find the issue better safe than sorry)
Here is the NetworkSender and NetworkReceiver classes:
public class NetworkSender extends Thread{
private Connection c;
private String msg;
public NetworkSender(Connection c, String msg){
this.c = c;
this.msg = msg;
}
public void run(){
try {
System.out.println("Trying to send");
c.sendObjects(msg);
System.out.println("Sent");
} catch (IOException e) {
e.printStackTrace();
}
}
}
public class NetworkReceiver extends Thread{
private Connection c;
private boolean running = true;
private Frame f;
public NetworkReceiver(Connection c, Frame f){
this.c = c;
this.f = f;
}
public void run(){
while(running){
System.out.println("running");
Object obj = null;
try {
obj = c.receiveObjects();
System.out.println("received");
} catch (ClassNotFoundException e) {
System.out.println("failed - class exception");
e.printStackTrace();
} catch (IOException e) {
System.out.println("failed - IO exception");
e.printStackTrace();
running = false;
}
if(obj != null){
if(obj instanceof String){
f.showMessage((String)obj);
}
}
}
}
public void kill(){
running = false;
}
}
The exact spot of breaking is in the NetworkSender class. In the console, I receive "Trying to send" but never "sent." This leads me to think that I'm setting up the threads wrong, the threads are somehow unable to talk to each other (sender and receiver threads), or the server/client system is done improperly for multi-threading.
I have looked up this issue extensively, but I could not find a solution anywhere that worked, so I apologize if there is a solution I over looked. If everything is checking out, I can post my connection, server, and client classes if needed, but I'm assuming they are functional since they work on the EDT. As I put nearly 4 hours scouring online, I ask that if you think this is a duplicate question you comment a link first, as I am almost sure I have seen it already lol.
The immediate reason is that you synchronize both receiving and sending on the Connection object itself. Meaning while one thread is inside receiveObjects(), no other thread can enter either send or receiveObjects(). Thus your receiving thread permanently blocks you from sending.
You could potentially make it work by removing synchronized from the methods on your connection class and instead making the respective methods on your client and server synchronize on selected different objects, for example the respective Input/Output-Streams.
Still, its a design desaster (not mincing words here). Your best course of action is probably to rethink the design - your choice of abstractions (or rather the lack of) and the choices you made with regards to assignment of responsibilities leave room for improvement.

Issue with Threads/sockets and MySql (Java)

I have a big problem with an exercise from my java teacher.
In theory the exercise must have the following points:
-Sockets
-Clients
-Server
-The server uses MySql for something
-Login
-Md5 to save the passwords
-Secure socket
With this I decide to make a chat in theory should be easy stuff but... I'm completely lose.
More or less I made the basic (Secure Socket, server, clients) but even that doesn't work, but the IDE makes no fail in theory should be fine.
Someone May help me?
The code is just below:
ChatClient this make work the client, loading the interface and the features:
public class ChatClient
{
private Socket s;
private ClientPanel panel;
public static void main(String[] args)
{
new ChatClient();
}
public ChatClient()
{
try
{
Window();
s = new Socket("localhost" , 5557);
ClientControl control = new ClientControl(s, panel);
}
catch (Exception e)
{
e.printStackTrace();
}
}
private void Window()
{
JFrame v = new JFrame();
panel = new PanelCliente(v.getContentPane());
v.pack();
v.setVisible(true);
v.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
}
}
ServerChat this create a server chat with secure sockets as one of the requisites of the exercise:
public class ServerChat extends Thread
{
public static void main(String[] args)
{
int port= 5090;
SSLServerSocketFactory sslserver = (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
try
{
SSLServerSocket sslsocket = (SSLServerSocket)sslserver.createServerSocket();
InetSocketAddress socketAddress = new InetSocketAddress("localhost" , port);
while(true)
{
SSLSocket socket = (SSLSocket)sslsocket.accept();
System.out.println("Client: " + socket.getInetAddress().getHostName() + " Conected");
}
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
public class ClientControl implements ActionListener, Runnable
{
private DataInputStream dataInput;
private DataOutputStream dataOutput;
private ClientPanel panel;
public ClientControl (Socket s, ClientPanel panel)
{
this.panel = panel;
try
{
dataInput = new DataInputStream(s.getInputStream());
dataOutput = new DataOutputStream(s.getOutputStream());
panel.addActionListener(this);
Thread t = new Thread(this);
t.start();
}
catch (Exception e)
{
e.printStackTrace();
}
}
public void actionPerformed (ActionEvent event)
{
try
{
dataOutput.writeUTF(panel.getTexto());
}
catch(Exception e)
{
e.printStackTrace();
}
}
public void run()
{
try
{
String text = dataInput.readUTF();
panel.addTexto(text);
panel.addTexto("\n");
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
Client Thread in theory this make posible to run the client as a thread and implements it's functions:
public class ClientThread implements Runnable, ListDataListener
{
private DefaultListModel conversation;
private Socket s;
private DataInputStream dataInput;
private DataOutputStream dataOutput;
public ClientThread (DefaultListModel conversation, Socket s)
{
this.conversation = conversation;
this.s = s;
try
{
dataInput = new DataInputStream(s.getInputStream());
dataOutput = new DataOutputStream(s.getOutputStream());
conversation.addListDataListener(this);
}
catch (Exception e)
{
e.printStackTrace();
}
}
public void run()
{
try
{
while (true)
{
String text = dataInput.readUTF();
System.out.println(text);
}
}
catch (Exception e)
{
e.printStackTrace();
}
}
public void intervalAdded(ListDataEvent e)
{
String text = (String) conversation.getElementAt(e.getIndex0());
try
{
dataOutput.writeUTF(text);
}
catch(Exception ex)
{
ex.printStackTrace();
}
}
#Override
public void contentsChanged(ListDataEvent arg0)
{
}
#Override
public void intervalRemoved(ListDataEvent arg0)
{
}
}
Client Panel is below basically makes a simple design with JSwing to create and interface where you see the conversation and you can writte whatever you want:
public class ClientPanel
{
private JScrollPane scroll;
private JTextArea textArea;
private JTextField textField;
private JButton button;
public ClientPanel(Container cont)
{
cont.setLayout(new BorderLayout());
textArea = new JTextArea();
scroll = new JScrollPane(textArea);
JPanel panel = new JPanel(new FlowLayout());
textField = new JTextField(50);
button = new JButton("Send");
panel.add(textField);
panel.add(button);
cont.add(scroll, BorderLayout.CENTER);
cont.add(panel, BorderLayout.SOUTH);
}
public void addActionListener (ActionListener action)
{
textField.addActionListener(action);
button.addActionListener(action);
}
public void addTexto (String text)
{
textArea.append(text);
}
public String getTexto()
{
String text = textField.getText();
textField.setText(text);
return text;
}
}
How can I add a database to Log in users?
How can I add there Md5 to protect the passwords?
How can I make this all work together?
That's my questions
You have a server and clients and want to write a chat. So the server is the center and holds the connection to the database where all persistent data is stored. The password is not stored as plain text, only it's md5 hash is stored in database.
Furthermore, only the server holds a connection to the database.
This answers where to use MD5 and which guy the master of the database is.
You have already created a SeverChat. That guy is responsible to listen for new clients to connect. If a new client wants to connect, the ServerChat has to spawn a new ClientController.
Your ClientControl does not look like what I mean. A ClientControll is responsible to take the request from the specific client he is connect to, handle the request and send an answer to the client.
That means you need some sort of a protokol. You can use ObjectStreams to send objects from the client to the sever and vice versa.
This makes it easier to define a protokol.
To get an idea of the ClientController:
class ClientController extends Thread {
private final ObjectInputStream dataInput;
private final ObjectOutputStream dataOutput;
private boolean loggedIn = false;
ClientController(ObjectInputStream dataInput, ObjectOutputStream dataOutput) {
this.dataInput = dataInput;
this.dataOutput = dataOutput;
}
#Override
public void run() {
try {
boolean stayConnected = true;
while (stayConnected) {
Object data = dataInput.readObject();
if (data instanceof LoginAction) {
// check data an do login
this.loggedIn = true;
dataOutput.write(new LoginResponse(/* response data */));
}
if (data instanceof RequestChatDataAction) {
if (this.loggedIn) {
dataOutput.write(new NotLoggedInResponse());
} else {
dataOutput.write(new ChatDataResponse(/* chat data.. */));
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
The LoginAction, LoginResponse a.s.o. objects define your protokol. You need of cause more objects to implement all features and these objects have to implement java.io.Serializable. Otherwise, you will not be able to send them over the wire.
You have to write counter part as well - the client.
The client starts up, connects to the server and tries to login. If login is successfull, the client waits for new chat data and displays it.
If the user types in something, this data is send to the server and will be added to the 'gobal' chat data.
I would recommend not to add the gui elements before the client-server communication is done. You can use the System.out and System.in to interact with the user.
So, I hope that helps you.
Furthermore, SO is not for questions like: Do my homework. I see that you already have taken the tour.
Reading How to create a Minimal, Complete, and Verifiable example would be appreciated.

Syncronizing a multithreaded server

Hello everyone i have created a multi threaded chat server that looks like this:
public class Main {
public static ServerSocket server;
public static Socket connection;
public static int backLog = 100;
public static int numberOfConnected;
public static boolean connected = false;
public final static int potNumber = 6080;
public static PrintWriter pw;
public static Scanner input;
public static int i = 0;
public static void main(String[] args) {
startServer();
}
public static void startServer(){
try {
server = new ServerSocket(potNumber, backLog);
waitingForConnection();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private static void waitingForConnection() {
connected = false;
i++;
while (!connected) {
try {
if (connected) {
}
connection = server.accept();
Server s = new Server(connection, pw = new PrintWriter(connection.getOutputStream()), input = new Scanner(connection.getInputStream()));
s.start();
numberOfConnected++;
waitingForConnection();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
The idea is that this is suppose to be a chat server so when one connects to the server it starts the following thread:
threads
public void run(){
while (connection.isConnected()) {
if (input.hasNext()) {
String fullMessage = input.nextLine();
if (fullMessage.equalsIgnoreCase("Connect")) {
connectHim();
}else {
chatMessage(fullMessage);
}
}
}
}
private void chatMessage(String fullMessage) {
String name = fullMessage.substring(0, fullMessage.indexOf(" "));
String message = fullMessage.substring(fullMessage.indexOf(" "), fullMessage.length());
pw.println(name+": "+message);
pw.flush();
}
private void connectHim() {
String name = input.nextLine();
pw.println(0);
pw.flush();
pw.println(1);
pw.flush();
pw.println();
pw.flush();
pw.println(name);
pw.flush();
}
So my problem is the following:
if the user that is bound to thread 1 (this is an example) and the user bound to thread 2 sends a message to the server how will i send that message to the user bound on thread 1?
One of options is to use Hashtable or HashMap (just call Collections.synchronizedMap(myMap) in case of Map usage). When you start new Thread, give him unique name (for example user nick name ) and put it to your collection where key - Thread name, and value - Thread as Object.
if the user that is bound to thread 1 (this is an example) and the user bound to thread 2 sends a message to the server how will i send that message to the user bound on thread 1?
For example you have user1, user2, user3. Now you build 3 Threads and put them to HashMap, like:
Map<String, Thread> threadMap = new HashMap<String,Thread>();
threadMap = Collections.synchronizedMap(threadMap);
YourThread th1 = new YourThread();
threadMap.put("user1", th);
YourThread th2 = new YourThread();
threadMap.put("user2", th);
YourThread th3 = new YourThread();
threadMap.put("user3", th);
....
Set<String> userSet = threadMap.keySet();
Iterator<String> it = userSet.iterator();
Thread currThread = null;
while(it.hasNext()){
String key = it.next();
currThread = threadMap.get(key);
// do something with currThread
}

Categories