thread overwritten when new socket connects (Server/Client) multithread java - java

I have to do a cluedo game for Uni, so we have a Server class and Clients that are connecting. For each Client connecting we want to start a own ServerThread with the socket of the Client that is connecting. This Thread just listens to incoming messages and tells the server class to send them back to the client(s).
PROBLEM: each time a new client connects he is overwriting this ServerThread so there is always just one ServerThread and we would like to have one for each Client. We send JSON messages between the Clients and right now the receive message in the ServerThread reads only from the last connected socket. How can i solve this? i added my accept method in the Server i guess the mistake is there but could be anywhere. Thanks for your help!
Mauritius
Server
public void accept() throws IOException{
while(true){
Socket socket = serverSocket.accept();
Runnable r = new ServerThreadHandler(socket);
Thread t = new Thread(r);
t.start();
}
}
ServerThreadHandler:
public class ServerThreadHandler implements Runnable {
static Socket socket=null;
protected User client;
//private static int i;
private static BufferedReader in;
private static OutputStreamWriter out;
public void createUser(String nick, String group, String[] ext) throws IOException{
client = new User(nick, group, ext, null, false, 0, false, socket, socket.getPort());
}
/**
* constructor-Method
* #param socketS
*/
ServerThreadHandler(Socket socketS){
socket = socketS;
}
public void run(){
Server.setThreadList(socket);
in = createReader();
out = createWriter();
//and so on...
}
}

The logic mentioned in you code snippet will definitely create as many threads as the no. of clients that are connecting.
However, the possible reason might be, since the Socket variable in ServerThreadHandler is Static, all subsequent threads being created overwrite the same socket variable causing issue in the previously created thread which is using the socket variable.
You should consider, using non static variable for the Socket in ServerThreadHandler since any runnable class should hold a state and should not be using a static socket.
From what I understood from your question,
createUser method is an instance method of ServerThreadHandler. Hence you must have created the instance of ServerThreadHandler to invoke createUser from another class. Hence you can access the socket variable even if it is an instance variable.

Unfortunately the code has many design flaws:
The quickest fix I can suggest is to remove User class and move everything in the Handler class (or vice verca ? )
also make all your variable non-static
static Socket socket=null;
protected User client;
//private static int i;
private static BufferedReader in;
private static OutputStreamWriter out;
they should be :
Socket socket=null;
protected User client;
//private int i;
private BufferedReader in;
private OutputStreamWriter out;

The Socket member variable should be non-static. Ditto the reader and writer.
Never make a variable static unless you have a really good reason to do so and understand the consequences.

Related

Detect first client thread to register in server

A simple version of my server code can be depicted as...
public class Server implements Runnable {
static boolean isFirstClient=false;
...
...
public void run(){
ServerSocket ss=new ServerSocket(port);
while(true){
Socket s= ss.accept();
if(!isFirstClient){
isFirstClient=true;
new ClientHandler(s,true);
}
else{
new ClientHandler(s,false);
}
}
}
...
...
}
Where client handler handles the client and second parameter in the ClientHandler determines whether its the first client or not and sends the packet accordingly to the client. (I wrote a different functionality for first client to register in the server and response from server determines the first Client.)
public class Client implements Runnable(){
boolean iamFirst=false;
public void run(){
InetAddress ip = InetAddress.getByName("localhost");
Socket soc = new Socket(ip, port);
...
// response from server is stored in responsePacket.
...
iamFirst=responsePacket.isFirst();
if(iamFirst){
...
...
}
else{
...
...
}
}
}
But because of large number of clients running at the same time and also use of static variable to detect first client in server it results in running more than 1 client threads as 'firstClient'.
Can anyone suggest the best way to distinguish the first client to register in server keeping in fact that huge number of clients start at the same time?
(Note: I don't want to use sleep() function in the code to seperate one client from other client to simulate a practical scenario.)
You can make isFirstClient volatile; this makes sure all threads see the latest value of the variable.
Another approach would be to synchronise the method where you accept the clients; but since you do that in a loop it would make no sense in this case.

How to synchronize a variable in main function to new thread?

I have a list of the socket in the main function, add a new socket when a new client connects to the server.
public static void main(String[] args) throws Exception {
// TODO code application logic here
server = new ServerSocket(port);
List<MySocket> sockets = new ArrayList<>();
//this is thread responsible to synchronizing
new SyncThread().start();
while(true){
Socket socket = server.accept();
MySocket mySocket = new MySocket(socket);
sockets.add(mySocket);
SocketThread.setSockets(sockets);
new SocketThread(mySocket).start();
}
}
Besides that, I also want to create a new thread that will synchronize the list of this socket to the client (by sending the list to clients periodically).
public class SyncThread extends Thread{
private static List<MySocket> sockets;
#Override
public void run(){
//send list sockets to client
}
}
How to I synchronize the list of the socket between the main function and SyncThread?
Make your list a synchronized list:
List<MySocket> sockets = Collections.synchronizedList(new ArrayList<>());
And then pass this as a constructor parameter to SyncThread:
new SyncThread(sockets).start(); // Need to add constructor parameter to class.
public class SyncThread extends Thread{
private final List<MySocket> sockets; // NOT static.
public SyncThread(List<MySocket> sockets) {
this.sockets = sockets;
}
...
}
Bear in mind that this doesn't make sockets synchronized for compound operations, e.g. iteration. For that, you'd need to explicitly synchronize on sockets; or choose a different type of list such as CopyOnWriteArrayList, which is inherently thread-safe (the choice depends on the read/write characteristics of how you use the list).
Additionally, it's rarely appropriate to extend Thread directly. Instead, pass it a Runnable:
new Thread(() -> { /* send list sockets to client */ }).start();

How do I call a method in a specific socket thread using "implements Runnable"?

I have a working Java Server (Although a tad rough around the edges) which contains 3 main classes.
The first class runs the server and gets the socket to listen on a port and passes new connections to a client handler.
The second class is a threaded client handler
The third is a protocol class which is called from the client handler and processes information. Once the information is processed, the protocol class returns a processed or formatted response back to the client handler to pass to the client.
The advantage is that the second class just needs to be loaded with what is acceptable data to accept from the socket. The data can be passed to the protocol handler, and the protocol handler can be loaded with whatever protocol you want the server to use to talk to the client.
In this instance I have loaded in a telnet-based chat class.
If, for example, someone leave the chat the client handler class may execute code such as:
for (i = 0; i < currentClientsConnected; i++) {
if(threads[i] != null && threads[i] != this) {
outputLine = threads[i].serverprotocol.processInput("** " + username + " has left the room **");
threads[i].out.printf(outputLine);
}
}
This passes "** [username] has left the room **" to the serverprotocol class, which then returns the data in the best best way to transmit the message to the clients. In this case the serverprotocol class formats the message with telnet control code which tells the client to re-draw the screen, add the new message and scroll up the existing current messages in the buffer.
I may also only want the client handler class to send message to sockets where the users are in certain chat rooms for example, so I will not want to always send to all the sockets.
In my code, this is Class 1 - the server class which accepts sockets with:
while (true) {
int i;
// Try and accept the connection
try {
clientSocket = serverSocket.accept();
// System.out.printf("Remote IP:");
// System.out.printf(clientSocket.getRemoteSocketAddress().toString());
// Find an unused socket if one is available
for (i = 0; i < maxClientsAllowed; i++) {
// If found create thread
if (threads[i] == null) {
(threads[i] = new clientThread(clientSocket, threads)).start();
break;
}
}
// If all sockets are taken
if (i == maxClientsAllowed) {
PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true);
out.printf("Server too busy. Try later.\n");
out.close();
clientSocket.close();
}
} catch(IOException e) {
System.out.println(e);}
}
and Class 2 is a class which extends thread:
class clientThread extends Thread {
private String clientName = null;
private DataInputStream in;
private PrintWriter out;
private Socket clientSocket = null;
private final clientThread[] threads;
private int currentClientsConnected;
private serverprotocol serverprotocol;
public clientThread(Socket clientSocket, clientThread[] threads) {
this.clientSocket = clientSocket;
this.threads = threads;
currentClientsConnected = threads.length;
}
public void run() {
//stuff
}
}
I have been trying desperately to see if I can get this working using implements Runnable instead, but I have had no luck in calling a thread's processInput (or maybe that should read dataToBeProcessed) method based on the instance number of the thread (Simply called i in the code here).
The closest I have seen in:
https://github.com/ico77/chat-server-client/blob/master/src/main/java/hr/ivica/chat/server/ChatServer.java
which can take advantage as running the server as a threaded pool server.
However the sendToAll function in this case writes directly to the PrintWriters associated to the socket via a HashMap. The server does not let you send to individual protocol handler classes, or even to the individual ChatServerWorker class instances. This means I can't, for example, send a message to socket 1 and 3 only and then a separate message to socket 2.
I can't find a single example online where an instance of a socket handler can be called without using extends Thread.
Specifically,I want to keep the ability to use lines like:
threads[i].out.printf(outputLine);
or
if(threads[i].[class].[var] == 'something') {
// stuff
}
Where an integer can be used to reference the thread instance, or any class vars or methods used by that thread.
Am I missing something?
Your big problem is that you are using the Threads themselves directly as the communication layer between the Server and the Client threads, something you should not do.
Instead, create your own interface Message objects that communicate the different information between the threads, and use LinkedBlockingQueue to process them.
You should probably have:
One queue for the server to receive messages
Depending on your implementation, one queue for each of the client threads to receive messages from the server, or one queue that's shared (if it's designed so that any thread can handle any message).
So you might do something like:
Message:
public interface Message {
accept(Server server);
}
Disconnection Message (I'm just going to do one):
public class DisconnectionMessage implements Message {
String username;
public void accept(Server server) {
server.handleMessage(this);
}
}
Server Runnable:
public void run() {
while(isServerOnline()) {
Message clientMessage = queue.poll();
clientMessage.accept(this);
}
}
public void handleMessage(DisconnectionMessage msg) {
// code
}
public void handleMessage(ConnectionMessage msg) {
// code
}
etc.
Client Runnable:
private final Socket socket;
private final BlockingQueue<Message> queue;
public Client(BlockingQueue<Message> queue, Socket socket) {
this.queue = queue;
this.socket = socket;
}
public void run() {
while(true) {
Message msg = receiveMessage();
queue.offer(msg);
}
}
I am not sure if I understood your question.
The short answer: if you want to make clientThread a Runnable, just do it and then change the line
(threads[i] = new clientThread(clientSocket, threads)).start();
into
(threads[i] = new Thread(new clientThread(clientSocket, threads))).start();
If you look at the documentation:
http://docs.oracle.com/javase/7/docs/api/java/lang/Thread.html#Thread(java.lang.Runnable)
Threads accept objects with Runnable supertype.
The long answer: you should not store threads directly but make an abstraction that represents a Client on the server side. This abstraction should encapsulate functionality for communication. That way, if you want to implement a different communication library you can easily subclass it and avoid breaking the open-close principle.
https://en.wikipedia.org/wiki/Open/closed_principle
Good luck.

Java - check if ObjectInputStream.readUTF() is null, or run in separate threads

I am trying to make a chat server (as a smaller part of a game I'm coding) that accepts two clients. The way I have done this so far is by creating two completely different sets of a Socket, ObjectInputStream, and ObjectOutput stream.
private JTextField userText;
private JTextArea chatWindow;
private ObjectOutputStream output;
private ObjectInputStream input;
private ObjectOutputStream output2;
private ObjectInputStream input2;
private ServerSocket server;
private Socket connection;
private Socket connection2;
static final int PORT = 6789;
The outputting is working just fine, but the input method is not working as planned. This is the input method:
//runs while conversation is active
private void whileChatting() throws IOException{
waitForConnection();
setupStreams();
String message = " You are now connected! ";
sendMessage(message);
ableToType(true);
do{
message = input.readUTF();
showMessage("\n" + message);
message = input2.readUTF();
showMessage("\n" + message);
}while(!message.contains("END"));
}
The line message = input.readUTF(); is waiting for there to be something to read. Is there a way to check if there is something to read and only set message equal to it if not null? No, if(input.readUTF() != null) does not work. Alternatively, I think there would be a way to do this with multiple threads, but I do not have a good grasp on how threads work, so if someone could give me an example, that would be very helpful.
Thanks.
readUTF() is considered a blocking call, which means when it is called, it will hold up the thread until it returns a value. Even if you were to nullcheck, it will still block your thread from continuing until something came through the stream (whether it be a string or a null).
To handle something like a multithreaded connection:
Create a class that implements Runnable
class User implements Runnable {
}
In that class, add you in\out stream. Make sure they're aren't static so they're instance variables. You are gonna want a new in/out stream for each connection
class User implements Runnable {
DataOutputStream out;
DataInputStream in;
Socket socket;
public User(Socket s) {
socket = s;
}
public void run() {
try {
out = new DataOutputStream(socket.getOutputStream());
//same with inputstream
String input;
while(!(input = in.readUTF()).equals("END")) {
//do something with input
}
}
}
}
When your server accepts a connection...
public static void main(String[] args) {
ExecutorService executors = Executors.newCachedThreadPool(); //contains your threads
ServerSocket ss;
while(true)
executor.execute(new User(ss.accept()));
}
ServerSocket.accept() is also a blocking call, which means the loop it's being called in will block (wait) until a user is accepted. This is called Blocking-IO.
All read calls from java.io are blocking.
DataInputStream.readUTF
DataInputStream.readInt
ObjectInputStream.readObject
If you want a system where methods such as these don't block, I suggest looking into the java.nio package (new IO). It far more advanced in my opinion, especially for someone who doesn't have a grasp on basic networking yet, but non-blocking IO's allow for your underlying OS to inform your application when to read/write (through a selector), thus removing the need for blocking calls.
Other than that, there is no way you can prevent readUTF to stop blocking, or somehow skip it without data coming through it.

Reading from a Java TCP socket in a thread

i have this TCP socket (i only posted relevant parts and removed exception throwings):
static Socket clientSocket;
static BufferedReader inFromServer;
The connection part (i call it from another class):
static Socket clientSocket = new Socket(ip, port);
static BufferedReader inFromServer = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
And to recieve text i have a runnable thread wich i call like this:
public static void StartRecievingText(){
TCPScanner.setReader(inFromServer);
Thread t1 = new Thread(new TCPScanner());
t1.start();
}
The thread:
public class TCPScanner implements Runnable {
static BufferedReader inFromServer;
public static void setReader(BufferedReader reader){
inFromServer = reader;
}
public void run() {
while (true) {
String temp = inFromServer.readLine();
System.out.println(temp);
}
}
}
The thread runs to the inFromServer.readline() part and appears to recieve nothing.
It's my first time working with threads and ...well second time working with tcp connections so i don't know if i've done anything wrong.
Thanks for your help (and sorry for spelling mistakes... still learning english)
Your client is reading lines but you aren't sending lines, so the client blocks forever waiting for a line terminator that never arrives. Either add a newline to what is being sent, or use another read method that doesn't require it.
There are other problems with your code. None of these data items should be static. Your read loop should test the result of readLine() for null, and close the socket and exit if true.

Categories

Resources