I am connecting to an device with opening an socket.
To get incoming data I perform an readaction on the InputStream in a different thread.
When I take away the electricity of the peer device I am connected to, my InputStream doesn't recognize the loss of connection.
This is my code to wait for input:
StringBuilder sb = new StringBuilder();
String result = "";
int c;
try
{
log.info( "waiting for data..." );
while ( ( ( c = inputStream.read() ) >= 0 ) )
{
if ( c == -1 )
{
log.info( "is -1" );
}
/*
* TODO: <LF> Can't always be the delimiter to define the end of an message. This should be
* parameterized.
*/
if ( c == 0x0a /* <LF> */ )
{
result = sb.toString();
sb.delete( 0, sb.length() );
}
else if ( c != 0x0d /* <CR> */ )
{
sb.append( (char) c );
}
if ( !result.isEmpty() )
{
log.info( getName() + ": received message: " + result );
listener.MessageReceived( result.getBytes() );
result = "";
}
}
log.info( "stream ended" );
disconnect();
listener.closed();
}
catch ( IOException | ResourceException e )
{
try
{
log.info( "in catch block" );
disconnect();
listener.closed();
throw new ResourceException( "An error occured during the receiving of a message for the device, or connection timed out.", e );
}
catch ( ResourceException e1 )
{
e1.printStackTrace();
}
}
This is inside of an JCA connector if that information is for use in any case.
To my knowledge the InputStream receives -1 when the Stream is interrupted and normally he should jump to my stream endedlog but it doesn't happen.
why doesn't it recognize that the connection can't be available, since the remote peer is powered off?
As you say, you don't want a timeout because you need to wait for the peer even if it doesn't send for hours. Barring special measures, there is no difference between a peer that doesn't send for hours and a peer that has been turned off. As long as no packets are sent, it's impossible to detect the difference.
You can do one thing to ensure that packets are sent: you can turn on the SO_KEEPALIVE socket option using the method Socket.setKeepAlive(true).
The problem is that you can't control from Java how often the keep-alive probes are sent. This typically depends on settings in your operating system kernel.
Still, it will allow you to detect a dead (or unreachable) peer quicker than "never".
A 'read timeout', as suggested by #Kayaman, IS the usual method of implementing a heartbeat. You need a 'timingOut' boolean, initialized to false. Whenever ANY data is received, data or heartbeat poll reply, set it to false. Upon read timeout check the 'timingOut' flag. If false, send a poll request and set 'timingOut' to true. If true, close socket and take your 'connection lost' action/s.
No need for a separate thread. No wasteful polling if data is being transferred often.
Related
Is it possible for a publisher to publish to multiple clients on the same machine using ZeroMQ? I'd like a set of clients, each of which can make standard Request/Response calls using SocketType.REQ and SocketType.REP, but which can also receive notifications using SocketType.SUB and SocketType.PUB.
I've tried to implement this topology, taken from here, although my version only has one publisher.
Here is my publisher:
public class ZMQServerSmall
{
public static void main(String[] args)
{
try (ZContext context = new ZContext())
{
ZMQ.Socket rep = context.createSocket(SocketType.REP);
rep.bind("tcp://*:5555");
ZMQ.Socket pub = context.createSocket(SocketType.PUB);
pub.bind("tcp://*:7777");
while (!Thread.currentThread().isInterrupted())
{
String req = rep.recvStr(0);
rep.send(req + " response");
pub.sendMore("Message header");
pub.send("Message body");;
}
}
}
}
Here is my proxy (I included a Listener to try to see what's going on):
public class ZMQForwarderSmall
{
public static void main(String[] args)
{
try
(
ZContext context = new ZContext();
)
{
ZMQ.Socket frontend = context.createSocket(SocketType.XSUB);
frontend.connect("tcp://*:7777");
ZMQ.Socket backend = context.createSocket(SocketType.XPUB);
backend.bind("tcp://*:6666");
IAttachedRunnable runnable = new Listener();
Socket listener = ZThread.fork(context, runnable);
ZMQ.proxy(frontend, backend, listener);
}
catch (Exception e)
{
System.err.println(e.getMessage());
}
}
private static class Listener implements IAttachedRunnable
{
#Override
public void run(Object[] args, ZContext ctx, Socket pipe)
{
while (true)
{
ZFrame frame = ZFrame.recvFrame(pipe);
if (frame == null)
break; // Interrupted
System.out.println(frame.toString());
frame.destroy();
}
}
}
}
Here is my Subscriber:
public class ZMQClientSmall
{
public static void main(String[] args) throws IOException
{
String input;
try
(
ZContext context = new ZContext();
BufferedReader stdIn = new BufferedReader(new InputStreamReader(System.in))
)
{
ZMQ.Socket reqSocket = context.createSocket(SocketType.REQ);
reqSocket.connect("tcp://localhost:5555");
ZMQ.Socket subSocket = context.createSocket(SocketType.SUB);
subSocket.connect("tcp://localhost:6666");
subSocket.subscribe("".getBytes(ZMQ.CHARSET));
while ((input = stdIn.readLine()) != null)
{
reqSocket.send(input.getBytes(ZMQ.CHARSET), 0);
String response = reqSocket.recvStr(0);
String address = subSocket.recvStr(ZMQ.DONTWAIT);
String contents = subSocket.recvStr(ZMQ.DONTWAIT);
System.out.println("Notification received: " + address + " : " + contents);
}
}
}
}
Here is the test. I open four terminals; 1 publisher, 1 proxy, and 2 clients. When I make a request in either of the two client terminals, I expect to see a notification in both, but instead I only see the notification in the terminal that made the request. I know that both clients are using the same address (localhost:6666), but I'd hoped that the proxy would solve that problem.
Can anyone see anything obviously wrong here?
Q : Is it possible for a publisher to publish to multiple clients on the same machine using ZeroMQ?
Oh sure, it is. No doubts about that.
Check the code. The responsibility of the order-of-execution is there. In distributed-systems this always so.
Once the [Client]-No1 instance gets a plausible .readLine()-ed input it will jump-in:
while ((input = stdIn.readLine()) != null)
{
reqSocket.send(input.getBytes(ZMQ.CHARSET), 0);
String response = reqSocket.recvStr(0);
String address = subSocket.recvStr(ZMQ.DONTWAIT);
String contents = subSocket.recvStr(ZMQ.DONTWAIT);
System.out.println( "Notification received: "
+ address + " : "
+ contents
);
}
Next it .send()-s over REQ and blocks (awaiting REP response)
Given the [Client]-No2 instance also gets a plausible manual .readLine()-ed input it will jump-in the same while(){...}, yet it will not proceed any farther than into again blocking wait for REP-response. That will not get .recv()-ed any time but after the -No1 got served from the REP-side, so while the -No1 might have gotten out of the blocking-.recv(), not so the -No2 ( which will still hang inside the its blocking-.recv() for any next REP-side response ( which may come but need not ), while the No1 has already proceeded to the PUB/SUB-.recv(), which it will receive ( but never the No2 ), next rushing into the next blocking-input-feed from .readLine() Et Cetera, Et Cetera, Et Cetera, ..., Ad Infinitum
So, these SEQ-of-In-Loop (REQ)-parts followed by (SUB)-parts in whatever number N > 1 of [Client]-instances, have effectively generated an EXCLUSIVE Tick-Tock-Tick-Tock clock-machine, mutually blocking an exclusive delivery of the PUB-ed in an N-interleaved order ( not speaking about the manual, .readLine()-driven, blocking step )
The ZMQServerSmall is not aware about anything wrong, as it .send()-s in-order to any .recvStr()-ed counterparty over REQ/REP and PUB-s to all counterparties ( that do not read autonomously, but only after 've been manually .readLine() unblocked and only then ( after REQ/REP episodic ( potentially infinitely blocked ) steps ) may .recv() its next ( so far not read message-part ( yet, there I do not see any code that works with explicitly handling the presence / absence of the multipart-flags on the SUB-side .recv() operations )
while (!Thread.currentThread().isInterrupted())
{
String req = rep.recvStr(0);
rep.send(req + " response");
pub.sendMore("Message header");
pub.send("Message body");;
}
The ZMQServerSmall in the meantime sends ( N - 1 )-times more messages down the PUB-broadcast lane, so the Tick-Tock-Tick-Tock MUTEX REQ/SUB-loop-blocking "pendulum" is not 2-State, but N-State on the receiving sides ( all receive the same flow of PUB-ed messages,yet interleaved by the N-steps of the REQ/REP MUTEX-stepping )
I am trying to create a monitor of messages between two applications. The idea is this monitor works in the middle of simple client/server application, and log the messages to the standard output. This program must be against of fails of the client/server (disconnections, time out's, etc). In the code, i call the client as "origin" and the server as "destiny". The problem is if the server dies after the first successfully connection, i don't know how do i ask that the destiny is still alive? (See catch exception in the code). I execute the next step's:
1.- I start the client/server application
2.- I start my program (with a Thread)
3.- I send one message from the client to my program, my program delivers this message to the server, the server answers to my program, my program delivers the message back to the client successfully.
4.- Now, i kill and restart the client/server application (without restarting my program)
5.- I repeat step "3" but at this time, when the program reaches the "len_message_from_destiny = streamFromDestiny.read(buffer_msg_destiny);" it produces the catch that i need to code for ask if the server is really alive (that is true in this step)". An attempt to read in this situation produces a "SocketException" with this description: "Software caused connection abort: recv failed java mail".
If i put in the code of catch that i need all instruction again for connect the socket and new streams, doesn't work too.
package interceptorprocess;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.net.SocketTimeoutException;
public class GenericInterceptorProcess implements Runnable
{
private final String prefix_log_messages;
public GenericInterceptorProcessConfigurations confs;
//COMMUNICATION'S ORIGIN'S VARIABLES
ServerSocket serverSocketLocal;
Socket socketForLocal;
DataInputStream streamFromOrigin;
DataOutputStream streamToOrigen;
int len_message_from_origen;
byte[] buffer_msg_origin = new byte[4096];
byte[] message_origin = null;
//COMMUNICATION'S DESTINY'S VARIABLES
Socket socketToDestiny;
DataInputStream streamFromDestiny;
DataOutputStream streamToDestiny;
int len_message_from_destiny;
byte[] buffer_msg_destiny = new byte[4096];
byte[] message_destiny;
GenericInterceptorProcess(GenericInterceptorProcessConfigurations confs_p)
{
confs = confs_p;
prefix_log_messages = confs.prefix_log_messages;
}
#Override
public void run()
{
//OCCASIONAL USE
String aux;
try
{
logger("STARTING SERVER --- PORT NUMBER: " + confs.local_port);
//CREATING THE LOCAL SERVER SOCKET
serverSocketLocal = new ServerSocket(confs.local_port);
//THIS LOOP MAINTAINS THE CONNECTIVITY WITH ONE CLIENT AT TIME
while ( true )
{
//CONNECTION TO THE ORIGIN
logger("WAITING FOR A CONNECTION OF A CLIENT...");
socketForLocal = serverSocketLocal.accept();
streamFromOrigin = new DataInputStream(socketForLocal.getInputStream());
streamToOrigen = new DataOutputStream(socketForLocal.getOutputStream());
logger("CONNECTED CLIENT: " + socketForLocal.getRemoteSocketAddress() );
//CONNECTION TO THE DESTINY
try
{
socketToDestiny = new Socket();
socketToDestiny.setSoTimeout(confs.timeout_destiny);
socketToDestiny.connect(new InetSocketAddress(confs.destiny_ip,confs.destiny_port),confs.timeout_connections);
//CREATING THE DESTINY'S STREAMS
streamFromDestiny = new DataInputStream(socketToDestiny.getInputStream());
streamToDestiny = new DataOutputStream(socketToDestiny.getOutputStream());
}
catch(IOException ex)
{
logger("CONNECTION REJECTED BY DESTINY: " + ex.getMessage());
closeOriginStream();
continue;
}
logger("CONNECTED DESTINY: " + socketToDestiny.getRemoteSocketAddress() );
//THIS LOOP MAINTAINS THE MESSAGES'S CHANGES
while ( true )
{
logger("WAITING FOR A MESSAGE..");
//THIS TRY/CATCH EXITS FOR CONNECTION RESETS
try
{
len_message_from_origen = streamFromOrigin.read(buffer_msg_origin);
}
catch(SocketException ex)
{
closeAll();
break;
}
if ( len_message_from_origen < 0 )
{
closeAll();
break;
}
message_origin = new byte[len_message_from_origen];
//SAVE THE ORIGIN'S MESSAGE INTO AN ARRAY WHO HAS THE EXACT SIZE OF THIS MESSAGE
System.arraycopy(buffer_msg_origin, 0, message_origin, 0, len_message_from_origen);
aux = new String(message_origin);
logger("RECEIVED MESSAGE FROM ORIGIN: " + aux);
//MAKE THE CHANGES IN THE INPUT'S MESSAGE
ChangesInMessages.makeChanges(message_origin,confs.type_changes_for_input_messages);
aux = new String(message_origin);
logger("RECEIVED MESSAGE FROM ORIGIN WITH MODIFICATIONS: " + aux);
//I HAD TO PUT THIS BLOCK BECAUSE IF THE DESTINY APPLICATIONS FAILS
//OR NOT ANSWER, THE PROGRAM MUST KEEP LISTENING THE FOLLOWING MESSAGES
try
{
//SENDING MESSAGE TO DESTINY
streamToDestiny.write(message_origin);
//READING THE ANSWER MESSAGE
logger("READING MESSAGE FROM DESTINY...");
//AT THIS POINY, WE MAY HAVE A PROBLEM IF THE SERVER DIES
len_message_from_destiny = streamFromDestiny.read(buffer_msg_destiny);
}
catch (SocketTimeoutException ex)
{
logger("IT DIDN'T COULD RETRIEVE A MESSAGE FROM DESTINY (timeout): " + ex.getMessage());
continue;
}
catch (SocketException ex)
{
boolean flagDestinyStillDead = false;
//IF WE REACH THIS EXCEPTION, IT MINDS THE DESTINY HAS DIED AFTER THE FIRST
//SUSSECCESFULLY CONNECTION, THUS, WE HAVE TO ASK IF THE DESTINY IS REALLY ALIVE
//HOW DO I DO THAT?
//I DONT KNOW HOW TO DO THIS SECCTION///
//NOTE: IF THE SERVER STILL DEAD, I HAVE TO CANCEL THIS MESSAGE AND
//RESTART THE LOOP
if ( flagDestinyStillDead )
{
closeAll();
break;
}
}
message_destiny = new byte[len_message_from_destiny];
//SAVE THE DESTINY'S MESSAGE INTO AN ARRAY WHO HAS THE EXACT SIZE OF THIS MESSAGE
System.arraycopy(buffer_msg_destiny, 0, message_destiny, 0, len_message_from_destiny);
aux = new String(message_destiny);
logger("RECEIVED MESSAGE FROM DESTINY " + aux);
//MAKE THE CHANGES IN THE OUTPUT'S MESSAGE
ChangesInMessages.makeChanges(message_destiny,confs.type_changes_for_output_messages);
aux = new String(message_destiny);
logger("RECEIVED MESSAGE FROM DESTINY WITH MODIFICATIONS: " + aux);
//SENDING THE ANSWER BACK TO THE ORIGIN
logger("SENDING BACK THE MESSAGE TO ORIGIN...");
streamToOrigen.write(message_destiny);
logger("MESSAGE DELIVERED SUCCESSFULLY!");
} //INTERNAL LOOP OF MESSAGES
} //INTERNAL LOOP OF CLIENTS
} //TRY
catch(IOException ex )
{
logger("THE SERVICE DIED: " + ex.getMessage() );
ex.printStackTrace();
} //CATCH
} //RUN
private void closeDestinyStream() throws IOException
{
streamFromDestiny.close();
streamToDestiny.close();
}
private void closeOriginStream() throws IOException
{
streamFromOrigin.close();
streamToOrigen.close();
}
private void closeAll() throws IOException
{
closeDestinyStream();
closeOriginStream();
}
private void logger(String message)
{
System.out.println(Utilidades.date() + " " + prefix_log_messages + " " + message);
}
}
Regards!
Sorry for my english, i am not a native speaker.
I will attempt to answer your question using my definition of "alive" and "dead" that I put in the comment. So we know that if the server does not respond within 5 seconds, it is dead. Also, if we could not connect to the server within 5 seconds, then the server is also dead.
We can check if it is alive/dead like this:
boolean flagDestinyStillDead = false;
//give the server 5 seconds to do whatever it needs to get back alive
try {
Thread.sleep( 5000 );
}
catch ( InterruptedException ie ) {
//ignore this. this probably won't happen unless you purposely cause it
}
//we now create a new connection, because the old connection died
socketToDestiny = new Socket();
//we try connecting to the server
try {
socketToDestiny.connect(new InetSocketAddress(confs.destiny_ip,confs.destiny_port), 5000 );
//if our connection was successful, we also need to create a new input and output stream
streamToDestiny = new DataOutputStream( socketToDestiny.getOutputStream() );
streamFromDestiny = new DataInputStream( socketToDesinty.getInputStream() );
//we give the server 5 seconds to respond to any of our messages
socketToDestiny.setSoTimeout( 5000 );
//ask the server if its alive
streamToDestiny.writeUTF( "Are you alive?" );
//if the server responds, then by our definition of "alive", the server is alive
String receivedMessage = streamToDestiny.readUTF();
if ( receivedMessage.equals( "Yes, I am alive now!" ) ) {
flagDestinyStillDead = false;
}
//if the server did not respond, then we would get a SocketTimeoutException
//and we never would reach here
}
catch ( SocketTimeoutException e ) {
//server had 5 seconds to accept our connection, and since the connection timed out
//we presume that the server is still dead
flagDestinyStillDead = true;
}
catch ( IOException e ) {
//we gave the server 5 seconds already to get back alive using Thread.sleep(...)
//if any of our communications fail, then the server must be dead.
flagDestinyStillDead = true;
}
So, here's our process in English:
1. We lost connection to the server, oh no!
2. Ok, well if it doesn't respond in around 5 seconds, then we'll
presume it died
3. Fine, we'll wait 5 seconds.
4. Ok, 5 seconds passed. Let's connect again with 5 second timeout.
4.1 Connection is reestablished. Ok, now we send the server a message to check that it can respond.
4.1.1 We send the server a message and it responds. Ok, it's alive
4.1.2 We send the server a message and it doesn't respond after 5 seconds. Ok, it's dead
4.2 Connection is not reestablished. Ok, well we already waited 5 seconds. Since the server won't connect even after 5 seconds is up, we presume it's dead.
Please note that when I do streamToDestiny.writeUTF( "Are you alive?" ), you'll need some kind of readUTF() code on the server to read this message. Then the server has to writeUTF( "Yes, I am alive now!" ); back. You'll have to modify this small part of the code to fit with however your server and client runs.
I am trying to create a monitor of messages between two applications. The idea is this monitor works in the middle of simple client/server application, and log the messages to the standard output. This program must be against of fails of the client/server (disconnections, time out's, etc). In the code, i call the client as "origin" and the server as "destiny". The current problem is when the server dies my program doesn't know and when a new message from client comes, this error appears "Software caused connection abort: socket write error". When the server comes up to life again, this error continues persisting. I think when i ask in the code "if ( !socketToDestiny.isConnected() )", it is not really connected. I am sure the problem is how i manage the "close" at the stream too.
This is the code of the program, i hope you could help me.
package interceptorprocess;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.net.SocketTimeoutException;
public class GenericInterceptorProcess implements Runnable
{
private final String prefix_log_messages = "[CONNECTOR]";
//COMMUNICATION'S ORIGIN'S VARIABLES
ServerSocket serverSocketLocal;
Socket socketForLocal;
DataInputStream streamFromOrigin;
DataOutputStream streamToOrigen;
int len_message_from_origen;
byte[] buffer_msg_origin = new byte[4096];
byte[] message_origin = null;
//COMMUNICATION'S DESTINY'S VARIABLES
Socket socketToDestiny;
DataInputStream streamFromDestiny;
DataOutputStream streamToDestiny;
int len_message_from_destiny;
byte[] buffer_msg_destiny = new byte[4096];
byte[] message_destiny;
#Override
public void run()
{
//OCCASIONAL USE
String aux;
try
{
logger("STARTING SERVER --- PORT NUMBER: " + "1234");
//CREATING THE LOCAL SERVER SOCKET
serverSocketLocal = new ServerSocket(1234);
//CREATING THE DESTINITY CONNECTION WITH 15 TIMEOUT'S SECONDS
socketToDestiny = new Socket();
socketToDestiny.setSoTimeout(15000);
//THIS LOOP MAINTAINS THE CONNECTIVITY WITH ONE CLIENT AT TIME
while ( true )
{
logger("WAITING FOR A CONNECTION OF A CLIENT...");
socketForLocal = serverSocketLocal.accept();
//CREATING THE ORIGIN'S STREAMS
streamFromOrigin = new DataInputStream(socketForLocal.getInputStream());
streamToOrigen = new DataOutputStream(socketForLocal.getOutputStream());
logger("CONNECTED CLIENT: " + socketForLocal.getRemoteSocketAddress() );
//THIS LOOP MAINTAINS THE MESSAGES'S CHANGES
while ( true )
{
logger("WAITING FOR A MESSAGE..");
len_message_from_origen = streamFromOrigin.read(buffer_msg_origin);
if ( len_message_from_origen < 0 )
{
closeOriginStream();
break;
}
message_origin = new byte[len_message_from_origen];
//SAVE THE ORIGIN'S MESSAGE INTO AN ARRAY WHO HAS THE EXACT SIZE OF THIS MESSAGE
System.arraycopy(buffer_msg_origin, 0, message_origin, 0, len_message_from_origen);
aux = new String(message_origin);
logger("RECEIVED MESSAGE FROM ORIGIN: " + aux);
//TRY TO CONNECT TO DESTINY
try
{
if ( !socketToDestiny.isConnected() )
socketToDestiny.connect(new InetSocketAddress("10.10.200.200",1234),5000);
}
catch(IOException ex)
{
logger("CONNECTION REJECTED BY DESTINY: " + ex.getMessage());
continue;
}
//CREATING THE DESTINY'S STREAMS
streamFromDestiny = new DataInputStream(socketToDestiny.getInputStream());
streamToDestiny = new DataOutputStream(socketToDestiny.getOutputStream());
logger("SENDING MESSAGE TO DESTINY: " + aux);
//I HAD TO PUT THIS BLOCK BECAUSE IF THE DESTINY APPLICATIONS FAILS
//OR NOT ANSWER, THE PROGRAM MUST KEEP LISTENING THE FOLLOWING MESSAGES
try
{
//SENDING MESSAGE TO DESTINY
streamToDestiny.write(message_origin);
//READING THE ANSWER MESSAGE
logger("READING MESSAGE FROM DESTINY...");
len_message_from_destiny = streamFromDestiny.read(buffer_msg_destiny);
}
//IN ONE OF THE FOLLOWINGS TWO CATCHS I GET THE ERROR
catch (SocketTimeoutException ex)
{
logger("IT DIDN'T COULD RETRIEVE A MESSAGE FROM DESTINY: " + ex.getMessage());
continue;
}
catch (SocketException ex)
{
//THE "socketToDestiny.isConnected()" ALWAYS RETURNS TRUE SINCE THE FIRST SUCCESSFULLY
//CONNECTION, AFTER THAT, IF THE SOCKET IS DISCONNECTED, IT REMAINS RETURNING "true".
//THUS, I HAD TO MAKE THE NEXT CODE BLOCK
streamFromDestiny.close();
streamToDestiny.close();
socketToDestiny.close();
socketToDestiny = new Socket();
socketToDestiny.setSoTimeout(confs.timeout_destiny);
socketToDestiny.connect(new InetSocketAddress(confs.destiny_ip,confs.destiny_port),confs.timeout_connections);
streamFromDestiny = new DataInputStream(socketToDestiny.getInputStream());
streamToDestiny = new DataOutputStream(socketToDestiny.getOutputStream());
logger("TRYING TO RECONNECT WITH DESTINY AND SEND THE MESSAGE... ");
logger("READING MESSAGE FROM DESTINY AFTER ERROR...");
len_message_from_destiny = streamFromDestiny.read(buffer_msg_destiny);
}
message_destiny = new byte[len_message_from_destiny];
//SAVE THE DESTINY'S MESSAGE INTO AN ARRAY WHO HAS THE EXACT SIZE OF THIS MESSAGE
System.arraycopy(buffer_msg_destiny, 0, message_destiny, 0, len_message_from_destiny);
aux = new String(message_destiny);
logger("RECEIVED MESSAGE FROM DESTINY " + aux);
//SENDING THE ANSWER BACK TO THE ORIGIN
logger("SENDING BACK THE MESSAGE TO ORIGIN...");
streamToOrigen.write(message_destiny);
logger("MESSAGE DELIVERED SUCCESSFULLY!");
} //INTERNAL LOOP OF MESSAGES
} //INTERNAL LOOP OF CLIENTS
} //TRY
catch(IOException ex )
{
logger("THE SERVICE DIED: " + ex.getMessage() );
ex.printStackTrace();
} //CATCH
} //RUN
private void closeDestinyStream() throws IOException
{
streamFromDestiny.close();
streamToDestiny.close();
}
private void closeOriginStream() throws IOException
{
streamFromOrigin.close();
streamToOrigen.close();
}
private void closeAll() throws IOException
{
closeDestinyStream();
closeOriginStream();
}
private void logger(String message)
{
System.out.println(Utilidades.date() + " " + prefix_log_messages + " " + message);
}
}
Regards!
Sorry for my english, i am not a native speaker.
According to Java API,
public boolean isConnected()
Returns the connection state of the socket.
Note: Closing a socket doesn't clear its connection state, which means this method will return true for a closed socket (see isClosed()) if it was successfuly connected prior to being closed.
Returns:
true if the socket was successfuly connected to a server
Since:
1.4
Note that even if you close the socket, isConnect() still returns true, so it's very likely that your isConnect() usage is not right.
According to Sumit Singh's answer to this question,
How do I check if a Socket is currently connected in Java?
socket.isConnected() returns always true once the client connects (and even after the disconnect) weird !!
So, even after disconnecting, isConnected() will return true. So my hypothesis (like yours) is that although you caught the SocketWrite exception, the isConnected() still returns true. I cannot test this out, because its not a working example. However, you can do something like this:
try {
//write message to server
} catch ( SocketException e ) {
//we lost the connection, right? then print if the socket is connected
System.out.println( socketToDestiny.isConnected() );
}
and see what the output is. If the output is still true, then we have discovered the problem. If my hypothesis is correct, I would propose that you try to reconnect in the catch statement. For example:
try {
//write message to server
} catch ( SocketException e ) {
//we lost the connection, so let's try to reconnect
while ( true ) {
try {
socketToDestiny.connect( ...ip address ... );
break;
} catch ( IOException e2 ) {
//keep trying to reconnect!
continue;
}
}
}
I have a socketserver set up with a remote client, and it is functional. Upon opening the client and logging in, I noticed that sometimes, there is an error that seems to be due to the client reading an int when it shouldn't be.
Upon logging on, the server sends a series of messages/packets to the client, and these are anything from string messages to information used to load variables on the client's side.
Occasionally, while logging in, an error gets thrown showing that the client has read a packet of size 0 or a very large size. Upon converting the large-sized number into ascii I once found that it was a bit of a string "sk." (I located this string in my code so it's not entirely random).
Looking at my code, I'm not sure why this is happening. Is it possible that the client is reading an int at the wrong time? If so, how can I fix this?
InetAddress address = InetAddress.getByName(host);
connection = new Socket(address, port);
in = new DataInputStream(connection.getInputStream());
out = new DataOutputStream(connection.getOutputStream());
String process;
System.out.println("Connecting to server on "+ host + " port " + port +" at " + timestamp);
process = "Connection: "+host + ","+port+","+timestamp + ". Version: "+version;
write(0, process);
out.flush();
while (true) {
int len = in.readInt();
if (len < 2 || len > 2000) {
throw new Exception("Invalid Packet, length: "+len+".");
}
byte[] data = new byte[len];
in.readFully(data);
for (Byte b : data) {
System.out.printf("0x%02X ",b);
}
try {
reader.handlePackets(data);
} catch (Exception e) {
e.printStackTrace();
//connection.close();
//System.exit(0);
//System.out.println("Exiting");
}
}
//Here is code for my write function (Server sided):
public static void write(Client c, Packet pkt) {
for (Client client : clients) {
if (c.equals(client)) {
try {
out.writeInt(pkt.size());
out.write(pkt.getBytes());
out.flush();
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
}
So looking at the write function, I don't really see how it could be confusing the client and making it read for the size of the packet twice for one packet (at least that's what I think is happening).
If you need more information please ask me.
The client side code looks fine, and the server side code looks fine too.
The most likely issue is that this is some kind of issue with multi-threading and (improper) synchronization. For example, maybe two server-side threads are trying to write a packet to the same client at the same time.
It is also possible that your Packet class has inconsistent implementations of size() and getBytes() ... or that one thread is modifying a Packet objects while a second one is sending it.
I'm studying the following basic Java socket code( source ). It's a Knock-Knock-Joke client/server app.
In the Client, we set up the socket as usual:
try {
kkSocket = new Socket("localhost", 4444);
out = new PrintWriter(kkSocket.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(kkSocket.getInputStream()));
} catch( UnknownHostException uhe ){ /*...more error catching */
And then later, we just read and write to Server:
BufferedReader stdIn = new BufferedReader(new InputStreamReader(System.in));
String fromServer;
String fromUser;
while ((fromServer = in.readLine()) != null) {
System.out.println("Server: " + fromServer);
if (fromServer.equals("bye."))
break;
fromUser = stdIn.readLine();
if (fromUser != null){
System.out.println("Client: " + fromUser);
out.println(fromUser);
}
And on the server, we have the corresponding code, to get the joke punch-line.
KnockKnockProtocol kkp = new KnockKnockProtocol();
outputLine = kkp.processInput(null);
out.println(outputLine);
while ((inputLine = in.readLine()) != null) {
outputLine = kkp.processInput(inputLine);
out.println(outputLine);
if (outputLine.equals("Bye."))
break;
I want to attach a heartbeat to the whole thing, which will print out to the console whenever it detects that the other side died. Because what happens now if I kill the other side is an exception - like this one below:
So if I am running both KnockKnockClient and KnockKnockServer, then I shut down KnockKnockServer, what should happen is that on the Client I see this outputted:
>The system has detected that KnockKnockServer was aborted
I'm looking for any tips. So far I've mainly been trying to run a daemon thread that periodially creates new connections to the other side. But I'm confused about what condition to check for(but I think it's just a boolean value?). Is that the right approach? I just found out online there's a library called JGroups for multicast networking - would that be a better way? I'm looking for any tips.
My server-code so far(sorry it's messy)
&
Client-side
thanks
But the exception you are getting is exactly this! It's telling you that the other side just died. Just catch the exception and print to the console, that "The system has detected that KnockKnockServer was aborted".
You are using TCP connection and TCP has built-in heartbeat (keepalive) mechanism that will do this for you. Just set setKeepAlive() on the socket. That being said - It is possible to control keepalive frequency per each connection, but I do not know how to do that in java.
http://tldp.org/HOWTO/TCP-Keepalive-HOWTO/overview.html
https://stackoverflow.com/a/1480259/706650
you have a Synchronous communication. for having the heartbeat message, use an asynchronous communication. there will be 2 threads. one will read from the socket and another will keep writing to the socket. If you use asynchronous communication, the server will be sending a message every 10 seconds. the client thread will be reading messages from the server and if there is no message, it means the server is down. in your case, the server either sends back the message to client(if client has some message) or send an automatic reply.your server code can be modified like this.
Create a server thread that will keep sending messages to client every 10 seconds.
public class receiver extends Thread{
public static bool hearbeatmessage=true;
Socket clientSocket=new Socket();
PrintWriter out=new PrintWriter();
public receiver(Socket clientsocket){
clientSocket=clientsocket;
out = new PrintWriter(clientSocket.getOutputStream(), true);
}
public void run(){
while(true)
{
if(heartbeatmessage){
thread.sleep(10000);
out.println("heartbeat");
}
}
}
}
In your server code:
KnockKnockProtocol kkp = new KnockKnockProtocol();
outputLine = kkp.processInput(null);
out.println(outputLine);
receiver r=new reciver(clientSocket);
r.run(); /*it will start sending hearbeat messages to clients */
while ((inputLine = in.readLine()) != null) {
outputLine = kkp.processInput(inputLine);
reciver.hearbeatMessage=false; /* since you are going to send a message to client now, sending the heartbeat message is not necessary */
out.println(outputLine);
reciver.hearbeatMessage=true; /*start the loop again*/
if (outputLine.equals("Bye."))
break;
The client code will also be modified, a thread will keep reading messages from the socket and if it has not received message for more than 11 seconds(1 second extra), it will declare the server is not available.
Hope this helps. There might be some flaw in the logic too. Let me know.
The following are best practices which we apply on a daily base when interfacing with hardware (using sockets).
Good practice 1 : SoTimeout
This property enables a read timeout. The goal of this is to avoid the issue that Tom had. He wrote something in the line of : "you will need to wait till the next client message arrives". Well, this offers a solution to that problem. And it's also the key to implementing a heartbeat and many other checks.
By default, the InputStream#read() method will wait forever, until a message arrives. The setSoTimeout(int timeout) changes this behaviour. It will apply a timeout now. When it timeouts it will throw the SocketTimeoutException. Just catch the exception, check a couple of things and continue reading (repeat). So basically, you put your reading method in a loop (and probably even in a dedicated thread).
// example: wait for 200 ms
connection.setSoTimeout(200);
You can use these interruptions (caused by the timeout) to validate the status: E.g. how long has it been since I received my last message.
Here is an example to implement the loop:
while (active)
{
try
{
// some function that parses the message
// this method uses the InputStream#read() method internally.
code = readData();
if (code == null) continue;
lastRead = System.currentTimeMillis();
// the heartbeat message itself should be ignored, has no functional meaning.
if (MSG_HEARTBEAT.equals(code)) continue;
//TODO FORWARD MESSAGE TO ACTION LISTENERS
}
catch (SocketTimeoutException ste)
{
// in a typical situation the soTimeout should be about 200ms
// the heartbeat interval is usually a couple of seconds.
// and the heartbeat timeout interval a couple of seconds more.
if ((heartbeatTimeoutInterval > 0) &&
((System.currentTimeMillis() - lastRead) > heartbeatTimeoutInterval))
{
// no reply to heartbeat received.
// end the loop and perform a reconnect.
break;
}
// simple read timeout
}
}
Another use of this timeout: It can be used to cleanly stop your session by setting active = false. Use the timeout to check if this field is true. If that's the case, then break the loop. Without the SoTimeout logic this would not be possible. You would either be forced to do a socket.close() or to wait for the next client message (which clearly makes no sense).
Good practice 2 : Built-in Keep-Alive
connection.setKeepAlive(true);
Well basically this is pretty much what your heart-beat logic does. It automatically sends a signal after a period of inactivity and checks for a reply. The keep-alive interval is operating system dependent though, and has some shortcomings.
Good practice 3 : Tcp No-Delay
Use the following setting when you are often interfacing small commands that need to be handled quickly.
try
{
connection.setTcpNoDelay(true);
}
catch (SocketException e)
{
}
I think you are over complicating things.
From the client side:
If the client gets an IOException for the connection reset, then this means the server is dead. Instead of printing the stack trace just do what ever you need to do once you know that the server is down. You already know the server is down due to the exception.
From the server side:
Either start a timer and if you don't get a request for a time more than the interval assume that the client is down.
OR start a background server thread at the client (making the client and server peers) and have the server send a "dummy" hearbeat request (server now acts as a client). If you get exception the client is down.
Figured I'd take a crack at this... I started with the KnockKnockServer and KnockKnockClient that are on the Java site (in your original question).
I didn't add any threading, or heartbeats; I simply changed the KnockKnockClient to the following:
try { // added try-catch-finally block
while ((fromServer = in.readLine()) != null) {
System.out.println("Server: " + fromServer);
if (fromServer.equals("Bye."))
break;
fromUser = stdIn.readLine();
if (fromUser != null) {
System.out.println("Client: " + fromUser);
out.println(fromUser);
}
}
} catch (java.net.SocketException e) { // catch java.net.SocketException
// print the message you were looking for
System.out.println("The system has detected that KnockKnockServer was aborted");
} finally {
// this code will be executed if a different exception is thrown,
// or if everything goes as planned (ensure no resource leaks)
out.close();
in.close();
stdIn.close();
kkSocket.close();
}
This seems to do what you want (even though I modified the original Java website example, rather than your code - hopefully you'll be able to see where it plugs in). I tested it with the case you described (shut down the server while the client is connected).
The downside to this is that, while the client is waiting for user input, you don't see that the server has died; you have to enter client input, and then you'll see that the server has died. If this is not the behavior you want, please post a comment (perhaps that was the whole point of the question - it just seemed like you might have been going down a longer road than you needed in order to get to where you wanted to be).
Here's a slight modification to the client. It doesn't use an explicit heartbeat, but as long as you keep reading from the server, you'll immediately detect the disconnect anyway.
This is because readLine will immediately detect any read errors.
// I'm using an anonymous class here, so we need
// to have the reader final.
final BufferedReader reader = in;
// Decouple reads from user input using a separate thread:
new Thread()
{
public void run()
{
try
{
String fromServer;
while ((fromServer = reader.readLine()) != null)
{
System.out.println("Server: " + fromServer);
if (fromServer.equals("Bye."))
{
System.exit(0);
}
}
}
catch (IOException e) {}
// When we get an exception or readLine returns null,
// that will be because the server disconnected or
// because we did. The line-break makes output look better if we
// were in the middle of writing something.
System.out.println("\nServer disconnected.");
System.exit(0);
}
}.start();
// Now we can just read from user input and send to server independently:
while (true)
{
String fromUser = stdIn.readLine();
if (fromUser != null)
{
System.out.println("Client: " + fromUser);
out.println(fromUser);
}
}
In this case, we allow client writes even when we're waiting for reply from the server. For a more stable application, we'd want to lock the input while we're waiting for a reply by adding a semaphore controlling when we start reading.
These are the modifications we would make to control the input:
final BufferedReader reader = in;
// Set up a shared semaphore to control client input.
final Semaphore semaphore = new Semaphore(1);
// Remove the first permit.
semaphore.acquireUninterruptibly();
new Thread()
... code omitted ...
System.out.println("Server: " + fromServer);
// Release the current permit.
semaphore.release();
if (fromServer.equals("Bye."))
... code omitted ...
while (true)
{
semaphore.acquireUninterruptibly();
String fromUser = stdIn.readLine();
... rest of the code as in the original ...
I think #Bala's answer is correct on server side. I'd like to give a supplementary on client side.
On client side, you should:
use an variable to keep the timestamp of the last message from server;
start a thread which runs periodically(every 1 second, e.g.) to compare current timestamp and the last message timestamp, if it is longer than desired timeout(10 seconds, e.g.), a disconnection should be reported.
Following are some code snippet:
The TimeoutChecker class(thread):
static class TimeoutChecker implements Runnable {
// timeout is set to 10 seconds
final long timeout = TimeUnit.SECONDS.toMillis(10);
// note the use of volatile to make sure the update to this variable thread-safe
volatile long lastMessageTimestamp;
public TimeoutChecker(long ts) {
this.lastMessageTimestamp = ts;
}
#Override
public void run() {
if ((System.currentTimeMillis() - lastMessageTimestamp) > timeout) {
System.out.println("timeout!");
}
}
}
Start the TimeoutChecker after connection is established:
try {
kkSocket = new Socket("localhost", 4444);
// create TimeoutChecker with current timestamp.
TimeoutChecker checker = new TimeoutChecker(System.currentTimeMillis());
// schedule the task to run on every 1 second.
ses.scheduleAtFixedRate(, 1, 1,
TimeUnit.SECONDS);
out = new PrintWriter(kkSocket.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(kkSocket.getInputStream()));
} catch( UnknownHostException uhe ){ /*...more error catching */
The ses is a ScheduledExecutorService:
ScheduledExecutorService ses = Executors.newScheduledThreadPool(1);
And remember to update the timestamp when receiving messages from server:
BufferedReader stdIn = new BufferedReader(new InputStreamReader(System.in));
String fromServer;
String fromUser;
while ((fromServer = in.readLine()) != null) {
// update the message timestamp
checker.lastMessageTimestamp = System.currentTimeMillis();
System.out.println("Server: " + fromServer);
if (fromServer.equals("bye."))
break;
Adel,was looking at your code http://pastebin.com/53vYaECK
Can you try the following solution. not sure whether it will work.
instead of creating a bufferedreader with the inputstream once,
we can create an instance of BufferedReader eachtime.
when the kkSocket.getInputStream is null, it comes out of the while loop and set completeLoop to false, so that we exit the while loop.
it has 2 while loops and the objects are created each time.
if the connection is open but does not have data in it inputstream will not be null,
BufferedReader.readLine would be null.
bool completeLoop=true;
while(completeLoop) {
while((inputstream is=kkSocket.getInputStream())!=null) /*if this is null it means the socket is closed*/
{
BufferedReader in = new BufferedReader( new InputStreamReader(is));
while ((fromServer = in.readLine()) != null) {
System.out.println("Server: " + fromServer);
if (fromServer.equals("Bye."))
break;
fromUser = stdIn.readLine();
if (fromUser != null) {
System.out.println("Client: " + fromUser);
out.println(fromUser);
}
}
}
completeLoop=false;
System.out.println('The connection is closed');
}