Issue with Threads/sockets and MySql (Java) - 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.

Related

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.

Display online users from server to all connected clients

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.

Nullpointer exception using networking with JavaFx GUI

sorry about the title I had trouble finding out what I should call it.
So here is the deal! I am currently creating a chat application where I use a Gui using I've created in JavaFx (a Gui that has some graphics on it but I think that is kinda irrelevant) what I have done so far is that I've setup a small server that each client connect to through the program! The main idea is that the clients sends a message to the server and the server will then send it to the other client (which is the whole idea in a chat program) one important note is that I am not using Threads and do not wish to yet!
So to get down to the real problem:
I've created a client class that contains methods to connect, receive and send. my Connect class works fine with my Gui and I am able to connect to the server without any problems!
The problem begins when I try to send to or receive from my server. No matter how many exceptions I throw or how many try Catch I do I get a nullpointer error! I've looked at the code for about 2 hours trying to figure out the problem but without luck! my code are as following:
Client class:
private PrintWriter pw;
/**
* #param args
* #throws IOException
*/
public void connect() throws IOException{
final int portNumber = 6040;
// du kan vælge at bruge inetadressen til at connecte i socketet.
InetAddress adr = InetAddress.getByName("localhost");
Socket socket = new Socket("localhost", portNumber);
pw = new PrintWriter(socket.getOutputStream());
// outPut - Programmet sender til serveren
pw.println("Connected waiting for input");
pw.flush();
//input - Serveren sender til programmet;
}
public void Send(String x) throws IOException{
if (x != null) {
pw.print(x);
pw.flush();
}else {
System.out.println("ingen meddelse");
}
}
public String getInformation(){
Scanner informationFromServer = new Scanner(System.in);
String x = informationFromServer.nextLine();
if (x== null) {
return "";
}
return x;
}
my simpleController code (the code that controls my GUI):
public class SimpleController implements Initializable{
public Button btn_Connect;
private Client client;
public Label chatPerson3;
public Label chatPerson1;
public Label lbl_Chatperson1_userName;
public TextField txt_userName;
public TextField textField_chat;
public TextField txt_ChatPerson1;
public Button Send;
public TextField txt_ChatPerson2;
#Override
public void initialize(URL location, ResourceBundle resources) {
// TODO Auto-generated method stub
btn_Connect.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
chatPerson1.setVisible(true);
lbl_Chatperson1_userName.setText(txt_userName.getText());
}
});
Send.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
String x = textField_chat.getText();
textField_chat.setText("");
txt_ChatPerson1.setVisible(true);
txt_ChatPerson1.setText(x);
System.out.println(x);
try {
client.Send(x);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
}}
and last but not least my main:
public class Main extends Application{
public static void main(String[] args) throws IOException{
Application.launch(Main.class, (java.lang.String[]) null);
}
#Override
public void start(Stage primaryStage) throws Exception {
try {
Client c = new Client();
c.connect();
AnchorPane page = (AnchorPane) FXMLLoader.load(Main.class.getResource("testingBackground.fxml"));
Scene scene = new Scene(page);
primaryStage.setScene(scene);
primaryStage.setTitle("Chatten");
primaryStage.show();
} catch (Exception ex) {
java.util.logging.Logger.getLogger(Main.class.getName()).log(
java.util.logging.Level.SEVERE, null, ex);
}
}
}
The exception I get when I try to send is of course in my client.send() method and if I try to receive before I send then it is in the client.getInformation() method.
What have I done wrong? What am I missing?

Java concurrent networking issues

I am a Java newbie trying to learn network programming and concurrency, and I thought I'd try out writing a simple chat server where input from a client is echoed to all the clients. That's not happening. I added a couple print statements so that the program will announce that it is waiting for connections and each time it receives a connection. I am using Telnet locally to connect to the port on my machine.
The program announces success for the first and second concurrent connections but then does not announce success for subsequent connections until I close all connections. So, for example, I'll connect from five separate terminals, and the program will announce "Connection 1" and "Connection 2" but will not announce "Connection 3", 4, and 5 until I close all the terminals.
I'm looking for help figuring out where my errors lie as well as general advice for how to approach debugging a situation like this.
In a nutshell, my program has
A Main class, which starts the other three threads
A ClientListener class, which uses a SocketReader to listen for connections and stores the Sockets inputstreams and outputstreams in two Sets.
A MessageReader, which iterates over the inputstreams. If it finds a message, it puts it in a SynchronousQueue and waits for the
MessageWriter to remove it. The MessageWriter sends the message to all the outputstreams.
The code is below. Thanks for any help!
public class Main {
public static void main(String[] args) {
ClientListener clientListener = new ClientListener();
Thread clientListenerThread = new Thread(clientListener);
clientListenerThread.setPriority(Thread.MAX_PRIORITY);
clientListenerThread.start();
MessageReader messageReader = new MessageReader(clientListener);
Thread messageReaderThread = new Thread(messageReader);
messageReaderThread.setPriority(Thread.MIN_PRIORITY);
messageReaderThread.start();
MessageWriter messageWriter = new MessageWriter(messageReader, clientListener);
Thread messageWriterThread = new Thread(messageWriter);
messageWriterThread.setPriority(Thread.NORM_PRIORITY);
messageWriterThread.start();
}
}
public class ClientListener implements Runnable {
private static final int DEFAULT_PORT = 5000;
private Set<Scanner> clientIn = Collections.synchronizedSet(
new LinkedHashSet<Scanner>());
private Set<PrintWriter> clientOut = Collections.synchronizedSet(
new LinkedHashSet<PrintWriter>());
public Set<Scanner> getClientIn() {
return clientIn;
}
public Set<PrintWriter> getClientOut() {
return clientOut;
}
#Override
public void run() {
try {
ServerSocket server = new ServerSocket(DEFAULT_PORT);
System.out.println("Listening for connections...");
int connectionNum = 0;
while(true) {
Socket socket = server.accept();
connectionNum++;
System.out.format("Connection %s%n", connectionNum);
Scanner in = new Scanner(socket.getInputStream());
PrintWriter out = new PrintWriter(socket.getOutputStream());
clientIn.add(in);
clientOut.add(out);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
public class MessageReader implements Runnable {
private ClientListener clientListener;
private BlockingQueue<String> messages = new SynchronousQueue<String>();
public MessageReader(ClientListener clientListener) {
this.clientListener = clientListener;
}
#Override
public void run() {
while(true) {
Set<Scanner> clients = clientListener.getClientIn();
synchronized (clients) {
for(Scanner client: clients) {
if(client.hasNext()) {
try {
messages.put(client.next());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}
public String getMessage() throws InterruptedException {
return messages.take();
}
}
public class MessageWriter implements Runnable {
private ClientListener clientListener;
private MessageReader messageReader;
public MessageWriter(
MessageReader messageReader,
ClientListener clientListener) {
this.messageReader = messageReader;
this.clientListener = clientListener;
}
#Override
public void run() {
try {
while(true) {
String message = messageReader.getMessage();
Set<PrintWriter> clients = clientListener.getClientOut();
synchronized (clients) {
for(PrintWriter client: clients) {
client.println(message);
}
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
I'm not a threading expert, but in class MessageReader there is this line
if(client.hasNext())
Javadoc for Scanner.hasNext() say's "This method may block while waiting for input to scan. The scanner does not advance past any input."
If the scanner is still in wait the synchronized method never proceeds and block all other inputs. And as said in my earlier comment the line which says clientIn.add(in); in class ClientListener probably gets blocked given that its a synchronized Set, but since the print statment is written before it, it might give the impression that Connection 2 was succesfully established.

Accessing shared variables from two threads in Java

I'm building an application in Java which requires a Hashtable to be accessed from instances of two classes and both extend threads. I have declared the Hashtable in one of the two classes. I always get null when i try to access the Hashtable contents from one of the classes. The other class is able to access the contents without any problem. I thought this was a problem of concurrency control. Since these are threads of different classes we cannot use synchronized methods. Is there a way to make the Hashtable accessible from threads of both the classes?
Here are the some parts of the code of my application
This is the class which stores the HashMap:
public class DataStore {
public Map ChatWindows ;
public DataStore()
{
ChatWindows = new ConcurrentHashMap();
}
public synchronized void putWindow(String with,ChatWindow t)
{
ChatWindows.put(with,t);
notifyAll();
}
public synchronized ChatWindow getWindow(String with)
{
notifyAll();
return (ChatWindow)ChatWindows.get(with);
}
public synchronized void ChatWindowOpen(chatClient cc,String with,String msg)
{
// chatWith = with;
ChatWindow t;
System.out.println(with);
t = getWindow(with);
if(t == null)
{
t = new ChatWindow(cc,with,msg);
// th = new Thread(t);
putWindow(with, t);
// th.start();
}
else
{
t.setVisible(true);
}
}
}
Two classes which access 'ChatWindows' HashMap
public class chatClient extends javax.swing.JFrame implements
Runnable,ListSelectionListener,MouseListener,WindowListener{
static String LoginName,chatWith,msgToChatWindow;
Thread listThread=null,th,chatListen;
static Socket soc;
static DataOutputStream dout,dout1;
static DataInputStream din,din1;
DefaultListModel listModel;
ChatWindow t;
public DataStore ds;
/** Creates new form chatClient */
public chatClient(Login l,DataStore ds) {
listModel = new DefaultListModel();
initComponents();
clientList.addListSelectionListener(this);
clientList.addMouseListener(this);
addWindowListener(this);
this.LoginName=l.loginName;
soc = l.soc2;
din = l.din2;
dout = l.dout2;
dout1 = l.dout1;
din1 = l.din1;
super.setTitle(LoginName);
listThread = new Thread(this);
listThread.start();
this.ds = ds;
}
.
.
.
.
public void mouseClicked(MouseEvent e)
{
chatWith = (String)clientList.getSelectedValue();
ds.ChatWindowOpen(this,chatWith,"");
}
This class has run() method too, but that doesn't use the HashMap. This class is able to access the 'ChatWindows' properly.'ChatListenThread' class is not able to access the contents of HashMap properly.
public class ChatListenThread implements Runnable{
DataOutputStream dout1;
DataInputStream din1;
public static chatClient cc;
public static ChatWindow t;
public DataStore ds;
public ChatListenThread(Login l,DataStore ds)
{
din1 = l.din1;
dout1= l.dout1;
this.ds = ds;
}
.
.
.
.
public void run(){
while(true)
{
try{
String msgFromServer=new String();
msgFromServer = din1.readUTF();
StringTokenizer st=new StringTokenizer(msgFromServer);
String msgFrom=st.nextToken();
String MsgType=st.nextToken();
String msg = "";
while(st.hasMoreTokens())
{
msg=msg+" " +st.nextToken();
}
ds.ChatWindowOpen(cc,msgFrom,msg);
}
catch(IOException e)
{
System.out.println("Read failed");
}
}
}
}
It's possible. Take a look at Sharing data safely between two threads.
Okey, I couldn't use your code because I don't understand, what I did see was that you want something like this:
Create a empty JFrame with a JTabbedPane and start a thread that connects to a Socket
When input comes on the socket, create a ChatPanel (~JTextArea) and add it to one of the tabs
Add the ChatPanel to a Map that handles the messages from "from"
Pass the message to the newly created ChatPanel
So I did that and I'm posting the code below! Hope that you can use it!
If you like to test this, first start the TestChatServer (code below) and then the ChatSupervisor.
This is the code for the client
public class ChatSupervisor extends JFrame implements Runnable {
JTabbedPane tabs = new JTabbedPane();
Map<String, ChatPanel> chats = new ConcurrentHashMap<String, ChatPanel>();
public ChatSupervisor() {
super("Test Chat");
add(tabs, BorderLayout.CENTER);
new Thread(this).start();
}
public void run() {
Socket sock = null;
try {
sock = new Socket("localhost", 32134);
Scanner s = new Scanner(sock.getInputStream());
while (true) {
String from = s.next();
String type = s.next();
String message = s.nextLine();
getChat(from).incomingMessage(type, message);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (sock != null) try { sock.close(); } catch (IOException e) {}
}
}
public ChatPanel getChat(String from) {
if (!chats.containsKey(from))
chats.put(from, new ChatPanel(from));
return chats.get(from);
}
public static void main(String[] args) {
ChatSupervisor cs = new ChatSupervisor();
cs.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
cs.setSize(400, 300);
cs.setVisible(true);
}
class ChatPanel extends JTextArea {
public ChatPanel(final String from) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
tabs.addTab(from, ChatPanel.this);
}
});
}
public void incomingMessage(final String type, final String message) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
append("[" + type + "]" + message);
append("\n");
}
});
}
}
}
This is the code for the test server:
public class TestChatServer {
public static void main(String[] args) throws Exception {
Socket s = new ServerSocket(32134).accept();
System.out.println("connected");
PrintWriter p = new PrintWriter(s.getOutputStream());
while (true) {
p.println("hello info Hello World!");
p.flush();
Thread.sleep(1000);
for (int i = 0; i < 10; i++) {
p.println("test" + i + " warn Testing for testing " + i);
p.flush();
Thread.sleep(100);
}
}
}
}

Categories