Handling multiple threads in a Client-Server architecture for File synchronization - java

I had to implement a Client-Server application in Java that automatically updates txt files in a Server directory depending on changes in the files in the Client side, for a homework assignment (had to, because I'm past the deadline).
I have a package that handles the changes in the files correctly, but I'm stumped about how to handle the changes in multiple files. My approach was using separate threads for each file in the client directory and using corresponding threads in the server directory for the same cause. This approach works for a single file, but not for multiples.
The code below is on the client side and calls a file's thread's checkfilestate method to handle the updates.
while(true){
for (Map.Entry<String, SynchronisedFile> entry : fileList.entrySet()) {
try {
System.err.println("SyncTest: calling fromFile.CheckFileState()");
sstt.start();
entry.getValue().CheckFileState();
} catch (IOException e) {
e.printStackTrace();
System.exit(-1);
} catch (InterruptedException e) {
e.printStackTrace();
System.exit(-1);
}
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
System.exit(-1);
}
}
And on the server side, if I start a single thread using:
Thread sstt = new Thread(new SyncThreadServer(sfileList.entrySet().iterator().next().getValue(),clientSocket));
sstt.start();
It works as expected. But if I start the serverside threads at the same time (which contains methods for decoding the Json messages from the input stream) using:
for (Map.Entry<String, SynchronisedFile> entry : sfileList.entrySet())
{
Thread sstt = new Thread(new SyncThreadServer(entry.getValue(),clientSocket));
sstt.setName(entry.getKey());
}
Threads of other files start reading JSON messages intended for other threads from the input stream. I'd like to be able to stop the serverside loop from starting the next thread, at least until the checkFile method is complete for one file/thread. But I still might run into problems after the initial stage, when all the treads are running at the same time. Any solutions on how to handle multiple threads in this case? (All threads use a single socket).
Edit: As I understand, this has to do with synchronization. Threads of other files on the server are accessing the Input stream before the first thread has even finished processing the inputs meant for it. This is the code of the server thread below. I need to somehow block the other threads from accessing the input stream before the first one has finished using it. Any help would be much appreciated. Thanks.
public class SyncThreadServer implements Runnable {
SynchronisedFile toFile; // this would be on the Server //Is an instance of the syncfile class, should be able to proc insts
Socket clientSocket;
public SyncThreadServer(SynchronisedFile tf, Socket aClientSocket){
toFile=tf;
clientSocket = aClientSocket;
}
#Override
public void run() {
Instruction inst = null;
InstructionFactory instFact=new InstructionFactory();
while(true){
{
try{
DataInputStream in = new DataInputStream(clientSocket.getInputStream());
DataOutputStream out = new DataOutputStream(clientSocket.getOutputStream());
String smsg = in.readUTF();
Instruction receivedInst = instFact.FromJSON(smsg);
System.err.println(smsg);
// The Server processes the instruction
toFile.ProcessInstruction(receivedInst);
//if(receivedInst.Type().equals("EndUpdate")){
// out.writeUTF("NEXT"); //TODO: Change to Json
// out.flush();}
//else
//{
out.writeUTF("GO"); //TODO: Change to Json
out.flush();
}
//}
catch (IOException e) {
e.printStackTrace();
System.exit(-1); // just die at the first sign of trouble
} catch (BlockUnavailableException e) {
// The server does not have the bytes referred to by the block hash.
try {
DataOutputStream out2 = new DataOutputStream(clientSocket.getOutputStream());
DataInputStream in2 = new DataInputStream(clientSocket.getInputStream());
out2.writeUTF("NGO"); //TODO: Change to Json
out2.flush();
String msg2 = in2.readUTF();
Instruction receivedInst2 = instFact.FromJSON(msg2);
toFile.ProcessInstruction(receivedInst2);
if(receivedInst2.Type().equals("EndUpdate")){
out2.writeUTF("NEXT"); //TODO: Change to Json
out2.flush();}
else
{
out2.writeUTF("GO"); //TODO: Change to Json
out2.flush();
}
} catch (IOException e1) {
e1.printStackTrace();
System.exit(-1);
} catch (BlockUnavailableException e1) {
assert(false); // a NewBlockInstruction can never throw this exception
}
}
// } //And here
}
}
}

Related

Multi-threaded Java TCP Client

I am writing a Java client application(Basic Java Net package with TCP/IP). The client must take input from the system.in and at the same time must listen to any messages coming from server through socket inputstream.
Once an input from the system.in is received, the client will get that input, do some processing and send it to the server as a request.
So basically 2 processes run,
-listening to client request
-listning to server responses.
I implemented 2 threads for this and ran the processing of messages in the main thread.
Is this good enough design.?
And is there a way to return the message received from the system.in to the main thread. The threads run() method returns void. I used a volatile variable to return the string received but its said that volatile is very costly since it doesn't use cpu cache to store the variable.
You can review these two projects I've written for an example of java sockets and multithreading.
Client
Server
I guess the ClientExample is the one you are searcing for but you can take a look at the server part too.
Basically the idea is to start two separate threads that listen for the different inputs - socket and console.
final Thread outThread = new Thread() {
#Override
public void run() {
System.out.println("Started...");
PrintWriter out = null;
Scanner sysIn = new Scanner(System.in);
try {
out = new PrintWriter(socket.getOutputStream());
out.println(name);
out.flush();
while (sysIn.hasNext() && !isFinished.get()) {
String line = sysIn.nextLine();
if ("exit".equals(line)) {
synchronized (isFinished) {
isFinished.set(true);
}
}
out.println(line);
out.flush();
disconnect();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
if (out != null) {
out.close();
}
}
};
};
outThread.start();
and another thread for the socket input:
final Thread inThread = new Thread() {
#Override
public void run() {
// Use a Scanner to read from the remote server
Scanner in = null;
try {
in = new Scanner(socket.getInputStream());
String line = in.nextLine();
while (!isFinished.get()) {
System.out.println(line);
line = in.nextLine();
}
} catch (Exception e) {
// e.printStackTrace();
} finally {
if (in != null) {
in.close();
}
}
};
};
inThread.start();
I hope this will help you :)

multithreaded server asynchronous java

Basically I need to make a server that handles multiple devices sending/receiving information. I have to be able to send commands to the devices. The number of devices is about 40 for now but will increase to maybe 400 over time. The devises will always send information once every 40seconds-60seconds which is set on the device so it can vary, but may also send more information depending on other factors, such as a responses to commands sent to it. So I have read there is java NIO which I can use or what I have currently done is created a thread for each incoming connection. The sending is not a constant thing so it needs to happen on demand, based on users input on my jsp website. So this is where I am stuck. How do I accomplish the sending of commands from outside the program where the connection is.
This is what I currently have:
Main server class to handle connections and make threads.
try (ServerSocket serverSocket = new ServerSocket(portNumber)) {
while (listening) {
ServerThread r = new ServerThread(serverSocket.accept());
Thread thread = new Thread(r);
thread.setDaemon(true);
System.out.println(thread.getId() + "thread");
thread.start();
thread.join();
}
} catch (IOException e) {
System.err.println("Could not listen on port " + portNumber);
System.exit(-1);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Then the ServerThread class:
public class ServerThread implements Runnable{
private Socket socket = null;
public AtomicBoolean isStopped=new AtomicBoolean(false);
public ServerThread(Socket socket) {
this.socket = socket;
}
public void run() {
while(!this.isStopped.get()){
try (
DataInputStream in = new DataInputStream(socket.getInputStream());
) {
ReceiveThread r = new ReceiveThread(in);
Thread thread = new Thread(r);
thread.setDaemon(true);
thread.start();
thread.join();
socket.close();
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
Then the ReceiveThread handles the reading/decoding.
On demand infrequent communication is better handled via UDP maybe with re-transmission implementation if you need to make sure that data is received, alternatively you can use NIO channels to handle that.
Creating a Thread for every client if the communication is infrequent is wasteful and pointless.

Making a small program part as a bigger one in java. Multithreading?. Noobs

I am working on a small project where I have to communicate to an Android app on my phone and with Arduino.
Now, I have the connection between Android and laptop (used as server, I have a small amount of data stored here), and I can change the contents of text files when I send certain instructions from Android app.
This is how I do it:
I have a ServerSide class that listens on port 3000 and I read the text I stream from phone, then I make certain changes in text files for different messages.
The code:
public class ServerSide {
public static void main(String[] args) throws IOException {
while (true) {
ServerSocket serverSocket = null;
// check if client is trying to connect
try {
serverSocket = new ServerSocket(3000);
} catch (IOException e) {
System.err.println("Cannot communicate on this port");
System.exit(1);
}
Socket clientSocket = null;
// move to another socket
try {
clientSocket = serverSocket.accept();
} catch (IOException e) {
System.err.println("Accept failed");
System.exit(1);
}
// stream that will be sent to client. "true" is for creating from
// existing
PrintWriter out = new PrintWriter(clientSocket.getOutputStream(),
true);
// stream that comes from the client
BufferedReader in = new BufferedReader(new InputStreamReader(
clientSocket.getInputStream()));
String recivedData, sendData;
ServerProtocol communicationProtocol = new ServerProtocol();
while ((recivedData = in.readLine()) != null) {
sendData = communicationProtocol.process(recivedData);
out.println(sendData);
System.out.println("The text should now be written in file");
System.out.println(sendData);
}
in.close();
out.close();
clientSocket.close();
serverSocket.close();
}
}
}
ServerProtocol.process() is the method that updates the files
By the way, this is a good version of a program that implies connection via sockets (if anyone should need information about this, at a future time).
Everything works great, I can see my updates immediatly after I send them, the server is up and running, waiting for messages.
I forgot to mention, I am new to java and a novice in programming, in general.
Now, I want this code I managed to write to be part of a bigger "server". By "server", I understand a program that "serves", performs a service. When it runs on my laptop, it takes information that comes from the Internet on the port I specify, change things in files according to my messages, keeps theese files updated and in the same time it uses theese files to "interpert" data I send from phone, and then sends according messages to Arduino Shield. (THIS IS WHAT I WANT TO ACHIVE)
I guess that what I miss, is the following:
How do i make this code I have written untill now, part of a bigger project, that does all that?
I managed to split the project in 3 parts:
Communication laptop - Android
Constant data updates
Communication laptop - Arduino
I've done some research, and I came across threads. So I thought about having the communication with Android on a separate thread of a MainServer. I clearly got it wrong, because it doesn't do what I expect it to do, so here is the code:
I create the ServerSide class that extends Thread, and has a run() method that should be called when I start the thread. It behaves just like the one above, but the executing code lays inside a run() method:
public class ServerSide extends Thread {
#Override
public void run() {
while (true) {
ServerSocket serverSocket = null;
// check if client is trying to connect
try {
serverSocket = new ServerSocket(3000);
} catch (IOException e) {
System.err.println("Cannot communicate on this port");
System.exit(1);
}
Socket clientSocket = null;
// move to another socket
try {
clientSocket = serverSocket.accept();
} catch (IOException e) {
System.err.println("Accept failed");
System.exit(1);
}
// stream that will be sent to client. "true" is for creating from
// existing
PrintWriter out = null;
try {
out = new PrintWriter(clientSocket.getOutputStream(), true);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// stream that comes from the client
BufferedReader in = null;
try {
in = new BufferedReader(new InputStreamReader(
clientSocket.getInputStream()));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
String recivedData, sendData;
recivedData = null;
sendData = null;
ServerProtocol communicationProtocol = new ServerProtocol();
try {
while ((recivedData = in.readLine()) != null) {
try {
sendData = communicationProtocol.process(recivedData);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
out.println(sendData);
System.out
.println("The text should now be written in file");
System.out.println(sendData);
}
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
try {
in.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
out.close();
try {
clientSocket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
serverSocket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
Then, I have the MainServer:
public class MainServer {
public static void main(String[] args) throws IOException {
System.out.println("Started");
Thread myThread = new Thread(new ServerSide());
myThread.start();
System.out.println("Started2");
while (true);
}
}
It should do nothing, just start the new thread. I expect this new thread do act just like the old ServerSide above (the one with main() method).
Someone, please tell me where I got it wrong !?!
Well, two things seem a little unusual about the MainServer class. First, creating a thread with new Thread(new ServerSide()) will cause a compilation error. There are two ways to fix this: either you make ServerSide implement the Runnable interface instead of extending Thread, or you create the thread with new ServerSide(). Second, the infinite loop at the end of main is useless and can be removed. The main method runs in its own thread, and if it finishes, all other threads keep running, and there is no need to keep main alive. The program will indeed keep running when main finishes, which may seem strange, but that's what will happen.
Everything was OK here, my problem was actually my phone connection to wi-fi, I was a bit too far in the back yard :)

Why does Java send needs Thread.Sleep

I am implementing a Server/Client system using Java. the server listens for incoming connection from clients and after a client connects, the server creates a new socket and passes it to a new thread which will only be used for receiving data:
while (true){
clientSocket=serverSocket.accept();
new ClientReceiver(clientSocket,this.clientsManager).start();
}
the clientReceiver class is as follows:
public class ClientReceiver extends Thread {
private Socket clientSocket=null;
private Client client=null;
private ClientsManager clientsManager;
private ClientActionParser clientActionParser=new ClientActionParser();
ClientHandlerState clientHandlerState;
PrintWriter outputStream=null;
BufferedReader inputStream=null;
public ClientReceiver(Socket clientSocket, ClientsManager clientsManager){
this.clientSocket=clientSocket;
this.clientsManager=clientsManager;
this.setClientHandlerState(ClientHandlerState.Connected);
}
public void run(){
String actionString;
try{
//define output and input stream to client
outputStream =new PrintWriter(clientSocket.getOutputStream(),true);
inputStream = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
//while client is connected read input to actionString
while((actionString=inputStream.readLine()) != null){
AbstractClientAction clientAction= this.clientActionParser.parse(actionString);
if(this.getClientHandlerState()==ClientHandlerState.Connected){
if(clientAction instanceof ClientLoginAction){
ClientLoginAction clientLoginAction=(ClientLoginAction) clientAction;
if(this.authenticate(clientLoginAction)){
}
else{
throw new AuthenticationException();
}
}
else{
throw new AuthenticationException();
}
}
}
if(this.getClientHandlerState()==ClientHandlerState.Authorized){
//receive other client actions: transfer barge ....
}
try {
Thread.sleep(400);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
catch(IOException e){
}
catch (AuthenticationException e) {
// TODO: handle exception
}
//clean up the resources
try{
outputStream.close();
inputStream.close();
clientSocket.close();
}
catch(Exception e){
}
}
private boolean authenticate(ClientLoginAction clientLoginAction){
//perform authentication. If authentication successful:
this.client=this.clientsManager.authenticateClient(clientLoginAction.getUsername(), clientLoginAction.getPassword());
if(this.client==null){
return false;
}
else{
ClientSender clientSender=new ClientSender(this.outputStream, this.client);
this.clientsManager.addClientSender(clientSender);
this.setClientHandlerState(ClientHandlerState.Authorized);
clientSender.start();
return true;
}
}
public ClientHandlerState getClientHandlerState(){
return this.clientHandlerState;
}
public void setClientHandlerState(ClientHandlerState clientHandlerState){
this.clientHandlerState=clientHandlerState;
}
after successful authentication in the receiver thread, a new thread is created for sending data to client and socket's outputStream is passed to the new thread.
the clientSender class contains a queue as a buffer which contains the data that should be sent to the client. here is class clientSender:
public class ClientSender extends Thread {
private Client client=null;
private final Log logger = LogFactory.getLog(getClass());
PrintWriter outputStream=null;
private Queue<String> clientEventsQueue= new LinkedList<String>();
public ClientSender(PrintWriter outputStream, Client client){
this.outputStream=outputStream;
this.client=client;
}
public void run(){
//System.out.println("ClientSender run method called.");
while(true){
try {
Thread.sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if(!this.clientEventsQueue.isEmpty()){
this.outputStream.println(this.clientEventsQueue.remove());
}
}
}
public Client getClient(){
return this.client;
}
public void insertClientEvent(String clientEvent){
this.clientEventsQueue.add(clientEvent);
}
whenever I want to send something to the client I use:
clientSender.insertClientEvent("some text");
the problem is that if I remove Thread.sleep(10) I will not receive anything in the client side. Since TCP sockets are blocking I think this should not happen. Is this normal or am I doing something wrong?
EDIT:
there is no "termination" for the sender thread. the server should send proper information to all clients whenever it receives an event from another system. so I think the best scenario is to stop the thread when there is no data to send and start it whenever there is. so I tried this in the clientSender class:
public void run(){
while(true){
if(this.clientEventsQueue.isEmpty()){
break;
}
else{
try {
this.outputStream.println(this.clientEventsQueue.take());
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
but now the problem is when to start the thread? I tried starting it whenever I want to send data but as I expected it does not work properly and only sends the fist package:
clientSender.insertClientEvent(clientEvent.getEventString());
clientSender.start();
EDIT2
I came up with this idea. It is very simple and I think it consumes so much less CPU time.
while(true){
while(this.clientEventsQueue.isEmpty()){
try {
Thread.sleep(300);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
try {
this.outputStream.println(this.clientEventsQueue.take());
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
as much as I tested it, it worked just fine. what do you think about it?
I see that you are using a LinkedList as a queue accessed by multiple threads and that you are doing a busy wait on it in the ClientSender.
This implementation is not thread safe and may cause problems like clientEvents posted on it not being made visible to the ClientSender thread, CPU being wasted etc.
You could use a BlockingQueue instead and call take() on it to block on the queue until an event is posted.
I also see that you are relying on sleep(400) to wait for the communication. That will also cause issues. The thread that is using the socket resource can close it when it's done, instead of this.
EDIT:
There are number of techniques to deal with terminating the thread. I think a "poison pill" will work well in this case. Basically you do:
String stuff = queue.take();
if (stuff == null) break;
and post null on the queue when you want to terminate it (doesn't have to be null, can be anything e.g. "terminate" etc.
EDIT2:
Your way of terminating won't work, as it will terminate immediately before anyone can post an event on it. Theoretically you could be spawning and then immediately killing the thread over and over etc. The easiest way to cope with this is to use a special message (aka "poison pill") for the termination condition.
As for having a thread only when there is an event, at that point I'd recommend using a thread pool. You could encapsulate the event sending into a Runnable, and hold the sockets in a Map. This is however quite complicated to implement and requires good understanding of multithreading to get it right. Multithreading is hard and can introduce severe headache when done wrong. Tbh I wouldn't recommend to try doing this without studying more about multithreaded programming.
EDIT3:
#user2355734: Polling the queue with an interval as you did is done by many people, but is discouraged. The take() method will in effect "sleep" and only wake up if there is something on the queue, so in theory by removing the "sleep" loop you should get even lower CPU usage and shorter latency. In general, you should try to avoid using "sleep" altogether in multithreaded code. It's rare that you genuinely need it and it's frequently a sign of broken/suboptimal code. As for tests, although they are useful it's hard or even pretty much impossible to guarantee correctness of multithreaded code through tests. Your code may run fine in your tests yet fail in production, under high load, under different environment etc. Therefore it's important to review the code and make sure it's theoretically correct.

Exception with ObjectInputStream

I have three classes, the client, the server and the handler (which is going to handle the server connections) as I show below:
// The Client
public void sendSomePackage() {
try {
socket = new Socket("localhost", 54321);
sos = socket.getOutputStream();
oos = new ObjectOutputStream(sockOutput);
} catch (IOException e) {
e.printStackTrace(System.err);
return;
}
// About to start reading/writing to/from socket
try {
Package package = new Package(100);
oos.writeObject(pacote);
} catch (IOException e) {
e.printStackTrace(System.err);
}
try {
Thread.sleep(50);
} catch (Exception e) {
e.printStackTrace();
}
// Done reading/writing to/from socket, closing socket.
try {
sock.close();
} catch (IOException e) {
System.err.println("Exception closing socket.");
e.printStackTrace(System.err);
}
//Exiting
}
Now the server class:
// The Server - with a method that just wait for connections
public void waitForConnections() {
while (true) {
try {
socket = serverSocket.accept();
// Server:Accepted new socket, creating new handler for it
SimpleHandler handler = new SimpleHandler(socket);
handler.start();
// Server:Finished with socket, waiting for next connection
}
catch (IOException e){
e.printStackTrace(System.err);
}
}
}
My handler, which just handle the server connections:
#Override
public void run() {
//Handler: Handler run() starting
while (true) {
try {
package = (Package) ois.readObject();
if (pacote != null) {
System.out.println("Package received " + pacote.getSourceid());
}
} catch (Exception e) {
e.printStackTrace(System.err);
break;
}
}
try {
// SimpleHandler:Closing socket
sock.close();
ois.close();
} catch (Exception e) {
// Handler: Exception while closing socket, e=" + e);
e.printStackTrace(System.err);
}
}
The idea is the client send some 'package' object to my server which is going to keep running receiving the 'package' object any time.
The connection works fine, but in the end of the program an exception is launched, this is the one:
Package received 100
java.io.EOFException
at java.io.ObjectInputStream$BlockDataInputStream.peekByte(Unknown Source)
at java.io.ObjectInputStream.readObject0(Unknown Source)
at java.io.ObjectInputStream.readObject(Unknown Source)
at br.ufscar.socket.SimpleHandler.run(SimpleHandler.java:45)
at java.lang.Thread.run(Unknown Source)
I already search for something on Google but nothing so far.
Any idea ?
This is working exactly as you want it to (probably). It reads the 100 then goes through the loop again (while(true) never stops looping until a break statement) and throws an exception because no more data has been sent and it goes to the catch statement and prints the error before exiting your while loop.
EOFException ist an IOException that indicates the end of an stream.
Here we say that if there aren't any more bytes to read then we should break out of the while loop before trying to read the object, etc.
while (true) {
if (ois.read() == -1) break;
//...rest of the code
}
Ok, this is how object streams work and the solution that works everywhere.
Object stream data is preceded by a 4 byte 'magical' sequence AC ED 00 05. An ObjectInputStream will peek for this data at construction time rather than before the first read. And that's logical: one wants to be sure it is a proper stream before being too far in an application. The sequence is buffered by the ObjectOutputStream at construction time so that it is pushed on the stream at the first write.
This method gives rise to complexities in buffered situations or transferring via sockets.
Fortunately there is a just as simple as effective solution to all these problems:
Flush the ObjectOutputStream immediately after construction!
ObjectOutputStream myStream = new ObjectOutputStream ( anotherStream );
myStream.flush();

Categories