I'am trying to set a timeout when a client try to connect to a server, if the server is down, the connection will wait 10 sec befor throwing the timeout exception.
In my case the code bellow throw the IOException without waiting, I really don't get it !
public boolean establishConnection()
{
System.out.println ("Connecting to " +
this.getServerHostname() + " au port " + this.getServerPort()+ " ...");
try {
SocketAddress sockaddr= new InetSocketAddress(_serverHostname, _serverPort);
_echoSocket = new Socket();
_echoSocket.connect(sockaddr,10000);
return _echoSocket.isConnected();
} catch (UnknownHostException e) {
System.err.println("Unknown Host: " + this.getServerHostname());
return false;
} catch (SocketTimeoutException e) {
System.err.println("Timeout");
return false;
} catch (IOException e) {
System.err.println("IOException : " +
this.getServerHostname() + ":" + this.getServerPort());
return false;
}
}
You'll only get a timeout if your connection request is not answered. If the server immediately rejects it, or if the server doesn't exist, you'll get an exception immediately.
But is this what you want to achieve?
If your intention is, in case the server is temporarily down, then try again after 10 sec then your approach is wrong.
You should try to do a connection to the server and if you get an exception because the server is down, you can sleep for 10 seconds and try the request again.
Otherwise Ernest's answer is correct
Related
I know there are tons of posts about stack overflow errors and i understand why my specific one is happening, my question is basically how to move away from recursion in this specific case. I have a class which establishes and maintains a client connection (for HL7 messaging specifically but it's essentially a glorified client connection) to another system which hosts corresponding server connections. This class' constructor starts a new thread and runs the following method :
#Override
public void connect()
{
try
{
setStatus("Connecting");
connection = context.newClient(intfc.getIp(), port, false);
connected = true;
setStatus("Connected");
logEntryService.logInfo(LogEntry.CONNECTIVITY, "Successfully connected " + connectionType + " client connection to "
+ intfc.getName() + "(" + intfc.getIp() + ") on port " + port);
monitor();
}
catch (HL7Exception ex)
{
connected = false;
setStatus("Disconnected");
try
{
TimeUnit.SECONDS.sleep(connectionRetryIntervalInSeconds);
connect();
}
catch (InterruptedException ex2)
{}
}
}
Upon successfully connecting with the server, the monitor method simply checks, in yet another thread, if the connection is still up at a given interval. If it goes down, the monitoring thread is interrupted and the connect() method is called again.
I did not anticipate this at first but you can quickly see why the connect() method is causing stack overflow errors after several days running. I'm struggling to think of a way to get the same functionality to work without the connect method calling itself again every time the connection fails.
Any suggestions would be appreciated.
Thanks!
Typically you'd use a Stack object to emulate recursion when required.
However, in your case, why are you using recursion at all? A while loop fits the purpose.
while(true /**or some relevant condition**/){
try{ //try to connect
....
catch(HL7Exception ex){
//sleep
}
}
I'm not sure of the purpose of your application, but there are may be better methods than sleeping. You could use a ScheduledExecutorService, but if it's a single threaded program with one purpose it's probably unnecessary.
When I had to deal with this issue in c# I used a Stack, and added new classes to it, instead of using recursion. Then a second loop would check to see if there were any objects in the stack that needed dealing with. That avoided stack overflow when I would have had huge amounts of recursion otherwise. Is there a similar Stack collection in Java?
Why are you calling the monitor() method in the first place? You mention that it is launched in a separate thread, then can't you just launch it in a new thread when the application comes up? Then there won't be a recursive call.
I changed my code to an iterative approach as suggested, works beautifully!
#Override
public void initThread()
{
initConnectionEntity();
mainThread = new Thread()
{
#Override
public void run()
{
while (running)
{
if (!connected)
{
try
{
connect();
}
catch (HL7Exception ex)
{
connected = false;
setStatus("Disconnected");
try
{
TimeUnit.SECONDS.sleep(connectionRetryIntervalInSeconds);
}
catch (InterruptedException ex2)
{}
}
}
try
{
TimeUnit.MILLISECONDS.sleep(500);
}
catch (InterruptedException ex2)
{}
}
}
};
mainThread.setName(intfc.getName() + " " + connectionType + " Main Thread");
mainThread.start();
}
#Override
public void connect() throws HL7Exception
{
setStatus("Connecting");
connection = context.newClient(intfc.getIp(), port, false);
connected = true;
setStatus("Connected");
logEntryService.logInfo(LogEntry.CONNECTIVITY, "Successfully connected " + connectionType + " client connection to "
+ intfc.getName() + "(" + intfc.getIp() + ") on port " + port);
monitor();
}
private void monitor()
{
monitoringThread = new Thread()
{
#Override
public void run()
{
try
{
while (running)
{
if (!connection.isOpen())
{
if (connected == true)
{
logEntryService.logWarning(LogEntry.CONNECTIVITY, "Lost " + connectionType + " connection to "
+ intfc.getName() + "(" + intfc.getIp() + ") on port " + port);
}
connected = false;
setStatus("Disconnected");
monitoringThread.interrupt();
}
else
{
connected = true;
}
TimeUnit.SECONDS.sleep(connectionMonitorIntervalInSeconds);
}
}
catch (InterruptedException ex)
{
logEntryService.logDebug(LogEntry.CONNECTIVITY, "Monitoring thread for " + connectionType
+ " connection to " + intfc.getName() + " interrupted");
}
}
};
monitoringThread.setName(intfc.getName() + " " + connectionType + " Monitoring Thread");
monitoringThread.start();
}
This question already has an answer here:
Must server & client have reverse sequence of claiming ObjectOutputStream & ObjectInputStream?
(1 answer)
Closed 4 years ago.
I am creating a client-server as follows:
Server:
Listener thread daemon (listening always for incoming connections)
Service object that send/receive data with clients connected
Client(s):
There can be many instances of clients
However, on either sides after connection is established, it takes forever to create Constructor of type ObjectOutputStream & ObjectInputStream. Bit of googling revealed this and this. I followed steps of :
1. creating ObjectOutputStream first
2. flush it
3. creating ObjectInputStream second
But this doesn't work for me. Wonder why ??
Server:
Listener Thread/daemon:
Socket connSocket;
try {
ServiceListener.serverSocket = new ServerSocket(listenPort);
System.out.println("Listening on port: " + listenPort);
while (true) {
connSocket = serverSocket.accept();
nodeList.add(connSocket);
System.out.println("Accepted connections ( " + connSocket + "):" + getConnectedNodeCount());
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Server Thread (After accepting Connection)
for (int i=0; i<listenerObj.getConnectedNodeCount(); i++) {
try {
System.out.println(listenerObj.nodeList.get(i));
serviceTx = new ObjectOutputStream(listenerObj.nodeList.get(i).getOutputStream());
serviceTx.flush();
serviceRx = new ObjectInputStream(listenerObj.nodeList.get(i).getInputStream());
String rxMsg = (String) serviceRx.readObject();
if (rxMsg.equals("HELLO")) {
System.out.println("Service received: " + rxMsg);
serviceTx.writeObject((Object) "HELLO");
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Client:
try {
System.out.println("Creating Node socket...");
clientSocket = new Socket(getServerIp(), getServerPort());
nodeTx = new ObjectOutputStream(clientSocket.getOutputStream());
nodeTx.flush();
nodeRx = new ObjectInputStream(clientSocket.getInputStream());
System.out.println("Connected to " + getServerIp() + ":" + getServerPort());
do {
String outBoundMsg = new String();
outBoundMsg = "HELLO";
System.out.println("Node sending \"" + outBoundMsg + "\" to service");
nodeTx.writeObject(outBoundMsg);
nodeTx.flush();
String rcvdMsg = (String) nodeRx.readObject();
if(rcvdMsg.equals("HELLO")) {
System.out.println("++++ client says " + rcvdMsg + " ++++");
}
} while(false);
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Server Console Output:
starting Listener 11...
Service Function started !!
Listening on port: 2244
Accepted connections ( Socket[addr=/127.0.0.1,port=62994,localport=2244]):1
Client Console:
Creating Node socket...
I would change the do { } while(false) to a do { } while(true) otherwise it make no sense to have a while loop that runs only once and exit, i.e. the do-while(false) loop acts just as if it is not there.
This is driving me insane!
I'm trying to implement TCP holepunching and as part of this I have a socket trying to connect continuously.
For some reason, after the first mobileSocket2.connect call times out, the second time a socket closed exception comes up. I have no idea why. As far as I can tell, a connection timeout shouldn't close the socket. so why does it say socket closed the second loop?
I bind a socket to the same local IP address and local port earlier on but close that socket.
Any help would be greatly appreciated.
Socket mobileSocket2 = new Socket();
try {
System.out.println("105");
mobileSocket2.setReuseAddress(true);
System.out.println("109");
mobileSocket2.setSoTimeout(50);
mobileSocket2.bind(new InetSocketAddress(myIPAddress.getHostAddress(), myPort));
System.out.println("bound");
}
catch (Exception e) {
System.out.println("caught 104: " + e.toString());
}
while(true){
Thread.sleep(5000);
try{
System.out.println("124");
mobileSocket2.connect(new InetSocketAddress(mobileAddress.getHostAddress(), mobilePort));
System.out.println("connection made: " + mobileSocket);
}
catch(Exception e){
System.out.println("exception 2 caught " + e.toString());
}
}
Your code is invalid.
You can't reconnect a connected Socket. When the connect succeeds you need to add a break statement.
You can't reuse a Socket when a connect() has failed. You have to close it and create a new one.
Either reopen the socket when the first exception is caught, or set the timeout to 0, which the javadoc says it is interpreted as 'infinite'. I didn't look at the Socket and SocketImpl code, but I'm fairly confident that, since Socket is a Closeable (and also an AutoCloseable), the implementation is along the lines of
public void connect(InetAddress address, int port) throws IOException {
try {
// connect to the other endpoint
} catch(/*any relevant exception*/) {
throw new IOException(/* ... */);
} finally {
this.close();
}
}
I'm trying to connect my Android APP to a Java server that I've made for it.
I have a problem, the server works good and the APP works fine too when connected to the server.
The problem comes when I close the server and try to connect to it. The suppose is that the Socket.connect() would throw an exception that I would catch, but this exception is not thrown.
I don't know what I'm doing bad, I paste my code here for you to read and maybe somone can help me. Thanks for all mates :D
Connection attributes:
static Socket s;
static DataOutputStream output;
static boolean connected;
The method who needs the connection:
public void enviarDatos(int r, int g, int b){
connect();
if(connected){
panel.setText(panel.getText() + "\nEnviando datos...");
try {
output.writeUTF(r + "," + g + "," + b);
} catch (Exception e) {
panel.setText("Error: " + e.getMessage());
}
disconnect();
}
}
The methods to connect and disconnect are there:
public void connect(){
try {
s = new Socket();
int timeout = 1000;
s.connect(new InetSocketAddress(SERVER_ADDRESS, SERVER_PORT), timeout);
output = new DataOutputStream(s.getOutputStream());
connected = true;
panel.setText("Conexion exitosa.");
} catch (Exception e) {
connected = false;
panel.setText("Error: " + e.getMessage());
}
}
public void disconnect(){
try{
output.close();
s.close();
connected = false;
} catch(Exception e){
panel.setText("Error: " + e.getMessage());
}
}
The first connect() method is different from the one you posted in the large code block where you present both the methods. It's pretty unclear which one you are using to connect. Try adding the int timeout parameter to the connect() like this:
int timeout = 1000; // 1s timeout
s.connect(new InetSocketAddress(SERVER_ADDRESS, SERVER_PORT), timeout);
This should make connect throw an IOException after the timeout expires.
Hope this solves your problem.
I see one potential issue in "disconnect". I think you're trying to close the socket when the output stream is still opened. In this case, the socket may not close properly which may cause issues in reopening. Although you should see an exception being thrown during closing.
In disconnect(), can you try closing output first before closing the socket?
public void disconnect(){
try{
output.close();
s.close();
connected = false;
} catch(Exception e){
panel.setText("Error: " + e.getMessage());
}
}
I don't have the context of this problem, but that's one potential issue I saw. Hopefully it helps.
I have a TCP Server and Client both written in Java and running on separate machines on Rhel 5.3 with jdk1.6. I have handled pretty much all the methods i could find to detect a disconnection on the "Server".
Following is a snippet of the Server code
private void listenforConnection() {
try {
socket = serverSocket.accept();
socket.setTcpNoDelay(true);
socket.setKeepAlive(true);
socket.setSoTimeout(5);
bosTcpOutStream = new BufferedOutputStream(socket.getOutputStream());
bisTcpInStream = new BufferedInputStream(socket.getInputStream());
log("New connection accepted from " + socket.getRemoteSocketAddress().toString());
sendHeartBeatsToClient();
} catch (IOException ie) {
log("Listener IOException : " + ie.getMessage());
}
}
private void sendHeartBeatsToClient() {
try {
while (true) {
long lngCurrentMillis=System.currentTimeMillis() ;
if ((lngCurrentMillis - lngLastSentMessageTime) >= 5000) {
byte[] bHeartBeat = getHeartBeatMessage();
bosTcpOutStream.write(bHeartBeat);
bosTcpOutStream.flush();
lngLastSentMessageTime = System.currentTimeMillis();
log("Heartbeat sent.");
} else {
try {
if (bisTcpInStream.read() == -1) {
log("Read Input Stream returned -1");
break;
}
} catch (SocketTimeoutException se) {
//Do nothing as i am not expecting the client to send anything.
} catch (IOException e) {
log("Read Input Stream error - " + e.getMessage());
break;
}
}
Thread.sleep(1);
}
} catch (IOException e) {
disconnectClientAndCloseSocket();
log("IO Exception" +e.getMessage());
} catch (InterruptedException e) {
disconnectClientAndCloseSocket();
log("Thread interrupted terminating." + e.getMessage());
}
}
I have also modified the tcp-keepalive kernel parameters on the "Server" machine as below:
net.ipv4.tcp_keepalive_time=2
net.ipv4.tcp_keepalive_probes=1
net.ipv4.tcp_keepalive_intvl=2
Now when i am simulating a disconnection by unplugging the network cable of the Client machine(after it has established the connection and received the initial data from the Server), I am seeing two different outcomes which i am unable to understand:-
If i unplug the cable after 10 to 15 seconds of successful client connection. On the "Server" I receive an IO Exception with "no route to host" after 10 minutes of unplugging the cable.
If i unplug the cable after 60 or so seconds of successful client connection. On the "Server" an IO exception is thrown with "Connection timed out" within 10 seconds. This is valid behavior keeping in mind the keep alive settings.
I have tried this a couple of times and i always get the same result.
What i don't understand is why the first outcome takes 10 minutes and it doesn't behave like the second outcome. Am i missing something?