calling methods from run() method in java multithreaded client-server architecutre - java

i am trying to call other methods in run() method. But only when i exit/terminate the client connection the methods are displaying the output.
For example: listall method should print when a client gives listall command. But it gets invoked only when client terminates the connection.
Can anyone please tell me what am i doing wrong here
public void run() {
try {
System.out.println("Client socket : "+ clientSocket);
clientPortNumber=clientSocket.getPort();
clients.add(clientSocket);
String line;
while(true) {
line=is.readLine();
//System.out.println(line);
if(line==null)
break;
String temp[]=line.split(" ");
if(temp[0].equals("ADD")) {
addRfc();//add method invocation
}
else if(temp[0].equals("LOOKUP"))
send(os);//send method invocation
else if(temp[0].equals("ListAll")) {
listAll(); /*listall method should print when cient gives listall command. But it gets invoked only when client terminates the connection*/
} else if(line.equalsIgnoreCase("quit")) {
break;
}
}
}
catch (IOException e) {
System.out.println(e);
}
}

Check the implementation of the client. It sounds like the client is buffered and you need to flush the request before the server receive the request.

Related

Server thread socket ignoring called method with readLine

I have a P2P network of nodes holding records of key:value, which can pass requests to other nodes on the network when the asked node doesn't hold the desired key. The operation always returns an "OK" or an "ERROR". However, when a server thread recieving the request passes it down to all the other connected nodes by calling a method, the anwser ("OK" or "ERROR") isn't captured by the method, but by the main loop in run().
Here is the simplified code:
the run() method of the server thread class:
public void run(){
String line;
try {
while (true){
line=in.readLine();
if(line!=null){
else{
switch (line.split(" ")[0]){
case "set-value":
out.println(setValue(line.split(" ")[1]));
break;
System.out.println("default:");
System.out.println(line);
break;
}
}
}
}
} catch (IOException e) {
System.out.println("connection closed with: "+socket.getInetAddress().getHostAddress()+":"+socket.getPort()+" (server socket)");
}
}
the setvalue() method:
private String setValue(String arg) throws IOException {
String setKey = arg.split(":")[0];
String setValue = arg.split(":")[1];
if(DatabaseNode.getKey().equals(setKey)){
DatabaseNode.setValue(setValue);
System.out.println("set-value successful, current record: "+DatabaseNode.getKey()+":"+DatabaseNode.getValue());
return "OK";
} else {
System.out.println("key not on this node, searching...");
for (ServerConnect sc : DatabaseNode.getConnectToClient()) {
System.out.println("sending set-value to: "+sc);
if(sc.sendRead("set-value "+arg ).equals("OK")) {
return "OK";
}
}
for (ServerThread st : DatabaseNode.getConnectedToServer()) {
if(st != this) {
System.out.println("sending set-value to: "+st);
if(st.sendRead("set-value "+arg).equals("OK")) {
return "OK";
}
}
}
}
return "ERROR";
}
and the problematic one, sendRead(), which is supposed to send a string and wait for the anwser, but instead is ignored and anwser is captured by the main run() method
public String sendRead(String str) throws IOException {
out.println(str);
String line;
System.out.println("sent "+str+" awaiting response...");
line = in.readLine();
System.out.println("got "+line);
return line;
}
Thank you for your help
I tried identifying the threads on incoming line, and I am absolutely sure that the same thread which is supposed to read from method just starts a new loop and does nothing with sendRead().
The socket is NOT static, autoFlush on BufferedReader is enabled.
I just figured out what was wrong, the readLine() call in run() steals the next line, leaving the method hanging.

HAPI - How to stop SimpleServer correctly and prevent further connections

I am building an application with several server and client HL7 connections managed by a CommunicationProcess class. Part of the application's functionality is to restart that process when new connections are added. Client connections do not pose a problem because, once the client side stops, there is nothing the server side can do to reconnect. For server connections however, I seem to be getting immediate reconnections from the (rather agressive) client side. This is the code I have to stop a server connection :
public void disconnect()
{
usageServer.getRemoteConnections().forEach((connection) -> connection.close());
usageServer.stopAndWait();
usageServer.getRemoteConnections().forEach((connection) -> connection.close());
}
public void stop()
{
running.set(false);
disconnect();
}
This is my implementation of connectionReceived :
#Override
public void connectionReceived(Connection theC)
{
if (running.get())
{
setStatus(ConnectionStatus.CONNECTED);
}
else
{
theC.close();
}
}
As you can see, the idea is to set a global AtomicBoolean to false when receiving the stop signal from the CommunicationProcess class, which denies any new connections, and stop the server. This, somehow, still allows the client to remain connected during this process. The client side is an application I'm not allowed to name but that has existed for well over a decade and I know for a fact it is not gonna be the issue because I've been supporting it as part of my day job for years and it simply does not behave like that.
Any idea why my code doesn't actually kill the connection? I feel like I've explored a lot of this API and I'm not finding a way to UNREGISTER a connection listener which would probably fix this. Also, there is no way that I can see to extend these server classes as everything is rather ferociously encapsulated and privatized.
Thanks
I was reviewing the code of the HAPI library.
The cause of the behaviour that you describe could be the following.
When the server starts, they creates a component named AcceptorThread. As it name implies, the responsability of this thread is initialize the ServerSocket that will be used to receive incoming client connections, and accept them.
This thread, as every Service abstraction proposed by the API, runs in a loop like this:
/**
* Runs the thread.
*
* #see java.lang.Runnable#run()
*/
public final void run() {
try {
afterStartup();
log.debug("Thread {} entering main loop", name);
while (isRunning()) {
handle();
startupLatch.countDown();
}
log.debug("Thread {} leaving main loop", name);
} catch (RuntimeException t) {
if (t.getCause() != null) {
serviceExitedWithException = t.getCause();
} else {
serviceExitedWithException = t;
}
log.warn("Thread exiting main loop due to exception:", t);
} catch (Throwable t) {
serviceExitedWithException = t;
log.warn("Thread exiting main loop due to exception:", t);
} finally {
startupLatch.countDown();
afterTermination();
}
}
When you invoke the method stopAndWait in the server, it will try to stop this thread also.
The stop process basically changes the boolean flag that controls whether the component ``ìsRunning()``` or not.
As you can see, although it sets the flag to false, the invocation of the method handle in the loop still must end.
This is the implementation of the AcceptorThread handle method:
#Override
protected void handle() {
try {
Socket s = ss.accept();
socketFactory.configureNewAcceptedSocket(s);
if (!queue.offer(new AcceptedSocket(s))) {
log.error("Denied enqueuing server-side socket {}", s);
s.close();
} else
log.debug("Enqueued server-side socket {}", s);
} catch (SocketTimeoutException e) { /* OK - just timed out */
log.trace("No connection established while waiting");
} catch (IOException e) {
log.error("Error while accepting connections", e);
}
}
As you can see, the method invokes ServerSocket.accept, thus allowing new incoming connections.
In order to disconnect this server side socket, we can call close from another thread.
In fact, this process is the one implemented by the AcceptorTread afterTermination method:
#Override
protected void afterTermination() {
try {
if (ss != null && !ss.isClosed())
ss.close();
} catch (IOException e) {
log.warn("Error during stopping the thread", e);
}
}
Unfortunally - you are right, the API is very close! - there is no a clear way to do that.
One possible solution could be implement your own HL7Service, name it, MySimpleServer, using the code of SimpleServer as a baseline, and just changing the implementation of the method afterTermination:
/**
* Close down socket
*/
#Override
protected void afterTermination() {
super.afterTermination();
// Terminate server side socket
acceptor.afterTermination();
// Terminate the acceptor thread itself
acceptor.close();
}
Please, pay attention: instead of call acceptor.stop() we invoke acceptor.afterTermination() to close directly the underlying server side socket.
To avoid the errors raised by the handle method in AcceptorThread, we can also implement a new class from the original one, or just trying to overwrite the handle method to take into account if the server side socket is closed:
#Override
protected void handle() {
try {
if (ss.isClosed()) {
log.debug("The server-side socket is closed. No new connections will be allowed.");
return;
}
Socket s = ss.accept();
socketFactory.configureNewAcceptedSocket(s);
if (!queue.offer(new AcceptedSocket(s))) {
log.error("Denied enqueuing server-side socket {}", s);
s.close();
} else
log.debug("Enqueued server-side socket {}", s);
} catch (SocketTimeoutException e) { /* OK - just timed out */
log.trace("No connection established while waiting");
} catch (IOException e) {
log.error("Error while accepting connections", e);
}
}
For testing, you can try something like this:
public static void main(String[] args) throws Exception {
HapiContext ctx = new DefaultHapiContext();
HL7Service server = new MySimpleServer(8888);
server.startAndWait();
Connection client1 = ctx.newClient("127.0.0.1", 8888, false);
server.getRemoteConnections().forEach((connection) -> connection.close());
server.stopAndWait();
try {
Connection client2 = ctx.newClient("127.0.0.1", 8888, false);
} catch (Throwable t) {
t.printStackTrace();
}
ctx.close();
System.exit(0);
}

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 :)

what is blocking the readLine() in this case? I tried sending \n or even byte arrays, is it a concurrency issue in my case?

I tried everything stack overflow has to offer on this common readLine problem. (sending \n, flushing out, changing to byte array style, becoming hermit, wrists )
I suspect in this case its a concurrency thing as Ispent well over 15 hours yesterday confirming that the only thing that isnt working is readline()!
I used loads of other versions like datareader with a byte array and making sure a \n got sent I even sent /ns just in case!
still my issue is the same, and I have ran out of ideas myself to solve the issue and have decided that somewhere, my problem is outside my understanding, just where? its got to be threading right?
I managed to get to read the socket to string that seemed to work so it IS blocking because reading the connection isnt working at all, the readline function is not the only way Ive had it as I said so in my snippets its not as developed as it has been but still the basic issue remains.
Please help, i dont know what the issue is
// So the main class initialises the socket objects and starts them in a thread, these work I get all sorts of flags letting me know that they are
void start_sockets() {
//if this is initiialised as a server and not a client
if (is_server) {
while (is_server) {
try {
System.out.println("listening for connection");
Sockject sj = new Sockject(server.accept());
sock_arr.add(sj);
System.out.println("server made connection ");
// once the connection is made the objects is started in a
// separate thread
new Thread(sock_arr.get(sock_arr.size() - 1)).start();
} catch (IOException e) {
}
}
} else { //else im running a client version of this class
// if the client socket isnt running in a thread, make it run
if (!running) {
new Thread(sj_client).start();
if (sj_client.sock.isConnected()) {
System.out.println("client thread connected to "
+ sj_client.sock.getLocalSocketAddress());
running = true;
}
}
}
}
//the inner class creates a socket object and puts it on an array or an object depending if the parent class is initialised to be a server or a client
class Sockject implements Runnable {
PrintWriter out;
BufferedReader in;
// a socket for processing
Socket sock;
// the constructor in this case initialises the input and output streams
Sockject(Socket s) {
sock = s;
try {
out = new PrintWriter(sock.getOutputStream());
in = new BufferedReader(new InputStreamReader(
this.sock.getInputStream()));
} catch (IOException e) {
close sockets
}
}
//tried variasions of this and similar, used data objects and been sennding /ns all over the shop
void recieve_data() throws IOException {
if (sock.isConnected()) {
if ((recieve = in.readLine()) != null) {
System.out.println("recieve says " + recieve);
}
}
}
// sends data to connection if it is cleared to send data
void send_data(String data) {
// send data called
if (clear_to_send == true) {
out.print(data);
out.flush();
clear_to_send = false;
}
}
#Override
public void run() {
while (threadloop ) {
try {
//code defo gets this far and with just send it keeps running forever so its defo recieve data thats the issue
send_data(send);
recieve_data();// <---I HATE YOU
} catch (IOException e) {
}
}
}
}
}
Now all of the above is ran in an instance of this class, in a thread of this class here these temporary functions are ran and are neversuccesfull
void servrecievex(){
System.out.println("NEVER GETS THIS FA THOUGH DOES IT");
for(int a = 0; a < net_flow.sock_arr.size(); a++){
if(net_flow.sock_arr.get(a).sock.isConnected()){
System.out.println("server recieve function");
net_flow.sj_client.clear_to_send = true;
net_flow.sock_arr.get(a).send_data("www /n \n");
System.out.println("RECIVEIFY!!!");
}
}
}
void clientsendx() {
net_flow.sj_client.clear_to_send = true;
net_flow.sj_client.send_data(Integer.toString(player1.posx) + "\n");
System.out.println("client sent stuff");
}

java socket server, client detect server has died

If I kill the Socket Server process, my Socket client process does not receive any errors, it continues to loop forever on the following code:
public void run() {
while(readData) {
String inputLine = null;
try {
while((inputLine = m_inputStream.readLine()) != null) {
//do stuff
}
} catch (IOException e) {
readData = false;
}
}
}
How can I detect that the socket server is gone and terminate the loop?
Terminate the outer loop when the call to readLine() returns null.
No exception is thrown when the server closes the connection normally. The stream should return null to signal the end of data.
This can be done with a loop like this:
public void run() {
try {
while (true) {
String line = input.readLine();
if (line == null)
break;
/* Process line. */
...
}
} catch (IOException ex) {
/* Handle the exception as desired. */
ex.printStackTrace();
}
}
Whilst the answer from erickson is correct, have you tried setting the socket read time-out properties? (e.g. sun.net.client.defaultReadTimeout). If it is possible that the server may take a long time responding, then this might be less useful as a solution to your problem but is a good idea nevertheless in many scenarios.

Categories