I am running some logic in a Thread that depends on a HTTP connection to a remote server. Currently, the thread crashes, if the remote server is not running. I want to modify the logic so that the thread waits for the remote server to become available again.
Technically, the solution seems strait forward. Something along the lines of:
boolean reconnect = false;
while (!reconnect) {
try {
URL url = new URL("my.remoteserver.com");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.connect();
reconnect = true;
} catch (Exception ex) {
// wait a little, since remote server seems still down
try {
Thread.sleep(5000);
} catch (InterruptedException e1) {
// if thread was interrupted while waiting then terminate thread
break;
}
}
}
However, this solution is not very elegant. Also, the use case seems so generic that I suspect this could be done by some helpful library. Alas, I could not find any - who can tell me how to improve my solution?
I think this use case is simple enough to implement yourself instead of introducing additional dependencies. If you are concerned about your solution not being very elegant I suggest refactoring it into a couple of smaller methods, for example like this:
public void connect() {
try {
connectWithRetries();
} catch (InterruptedException e) {
// Continue execution
}
}
private void connectWithRetries() throws InterruptedException {
while (!tryConnect()) {
sleep();
}
}
private boolean tryConnect() {
try {
URL url = new URL("my.remoteserver.com");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.connect();
} catch (Exception e) {
return false;
}
return true;
}
private void sleep() throws InterruptedException {
Thread.sleep(5000);
}
Camel provides support for these kind of use-cases : http://camel.apache.org/http
However it is more a framework to build data-stream/event-driven applications so it might be a very big hammer to retry a connection to an http server. However, if it fits the application it is a great library/framework to move data around.
Related
Very new to Java in particular, using the SimpleFTP library to send a file to a server.
It seems like any method call on a SimpleFTP object seems to require being inclosed in a try-catch. What is the proper way to disconnect from the server, then?
For example:
private void ftp()
{
int portNumber = 21;
SimpleFTP ftp = new SimpleFTP();
try
{
ftp.connect("serverAddress", portNumber, "userName", "password");
ftp.bin();
ftp.cwd("dir");
ftp.stor(new File("filePath"));
}
catch (IOException e)
{
e.printStackTrace();
}
finally
{
ftp.disconnect();
}
}
This does not compile, because of the content in fianlly's body. If I move it up to the try block and scrap the finally, it'll compile... But what if my app connects to the server, then throws an exception while doing the other tasks?
What you didn't mention is that the reason you're having a problem is that disconnect() is also declared to throw an IOException.
Looking at the source for SimpleFTP you find:
public synchronized void disconnect() throws IOException {
try {
sendLine("QUIT");
}
finally {
socket = null;
}
}
All it's doing is sending the QUIT command to the remote FTP server then just dropping the reference to the socket in its finally block. If that throws .... it means the socket is already dead, but since you're disconnecting you really don't care (If I'd written that client, i'd have caught and ignored the exception for that reason and not had it throw).
In your finally block just wrap it in it's own try/catch block and don't do anything in the catch block. Option B is just putting it in the try block. The only reason it's going to throw is if the socket is already disconnected and letting the SimpleFTP instance fall out of scope after an exception will clean things up just as well.
Surround the disconnect call with its' own try catch block...
finally
{
if (ftp != null) {
try {
ftp.disconnect();
} catch (Exception e) {
e.printStackTrace();
}
}
}
There is a component in my application that listens to a server via TCP (so it only receives data, the output-stream is never used). The only reason for a potential disconnect are technical issues. From a logical point of view, the connection should stay open forever.
I know that I have to implement some kind of ping/pong strategy if I want to detect a connection failure immediately. But in my case, it is not necessary to detect a dropped connection immediately as long as it gets detected at all (let's say some minutes or hours later).
My questions:
If I don't use some kind of pingpong/alive-check strategy and the connection drops, will I get an IOException in my application logic some time later (it would be okay if it took some hours) or is it possible that the dropped connection isn't detected at all?
Would the code below fit my requirements? It's a bit ugly (many try-catch/while(true) and even sleep, but I'm wondering if a timed out connection could be recognized after a certain amount of time (e.g. due to an IOException in the blocking BufferedReader.readLine method).
Apart from the questions above, what could I do better?
public class Receiver implements Runnable {
private Socket socket;
private final String host;
private final int port;
private final int connectionRetryAfter = 10* 1000;
public Receiver(String host, int port) { // assignments... }
#Override
public void run() {
tryCreateSocket();
listenToServer();
}
private void listenToServer() {
String receivedLine;
BufferedReader buf;
while(true) {
try {
buf = new BufferedReader(new InputStreamReader(socket.getInputStream()));
while ((receivedLine = buf.readLine()) != null) {
// do something with 'inputLine'
}
} catch (IOException e) {
// logging
} finally {
closeSocket();
}
// At this point, either an exception occured or the stream equals null (which means it's closed?)
tryCreateSocket();
}
}
private void tryCreateSocket() {
try {
socket = new Socket(host, port);
} catch (IOException e) {
// logging
try {
Thread.sleep(connectionRetryAfter);
} catch(InterruptedException ex) {
// logging
Thread.currentThread().interrupt();
}
// retry
tryCreateSocket();
}
}
private void closeSocket() {
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
// logging
}
}
}
}
listenToServer() should certainly throw an IOException if the connection/reconnection attempt fails. Consider the case when the server is down. Do you really want to loop inside this method forever?
One problem you might need to avoid is that you tryCreateSocket() makes a recursive call. If your client is disconnected for a very long time you might run out of memory. Further more when you do reestablish connection the memory stack is not freed.
I would recommend an iterative while loop calling the tryCreateSocket() to avoid this problem.
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.
below is a static method for checking if the other side RMI server is online, i basically call a method that if it replies true it means the connection is on, if it does not reply and instead gives a exception it means something is wrong. Is there a better way to do it? And is there a better way to speed up the process? If there is connectivity it returns with the value fast, but if not it takes sometime.
public static boolean checkIfOnline(String ip,int port)
{
boolean online = false;
try {
InetAddress ipToConnect;
ipToConnect = InetAddress.getByName(ip);
Registry registry = LocateRegistry.getRegistry(ipToConnect.getHostAddress(),port);
ServerInterface rmiServer = (ServerInterface)registry.lookup("ServerImpl");
online = rmiServer.checkStudentServerOnline();
if(online)
{
System.out.println("Connected to "+ipToConnect);
}
} catch (RemoteException e) {
System.out.println(e.getMessage());
//e.printStackTrace();
return false;
} catch (NotBoundException e) {
System.out.println(e.getMessage());
//e.printStackTrace();
return false;
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return online;
}
The best way to test whether any resource is available is simply to try to use it. That will either succeed or fail, and the failure tells you that it wasn't available (or something else went wrong).
Any approach based on executing additional code beforehand is merely attempting to predict the future. It is liable to several problems, among them testing the wrong thing and changes of status between the test and the usage.
I'm working on a web server for Android and even though I've spent days trying to fix it, I'm at my wits' end with this particular bug. I'm trying to read the request from the browser, and the code works fine most of the time, but something like 5% of the requests fail and it throws random SocketTimeoutExceptions without even reading a single character from the Socket.
I have tested this with different browsers and it happens with all of them, so chances are the problem is on my end. Here's the relevant code, stripped down as far as possible:
public class ServerThread extends Thread {
private ServerSocket ss = null;
private boolean isRunning;
private ExecutorService threadPool = new ThreadPoolExecutor(2, 12,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>(),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.CallerRunsPolicy());
public ServerThread() {
}
public synchronized void run() {
ss = new ServerSocket(8080, 1);
isRunning = true;
while (isRunning) {
Socket clientSocket = null;
try {
if (ss != null) {
clientSocket = ss.accept();
if (isRunning) {
this.threadPool.execute(new HTTPSession(clientSocket));
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
And:
public class HTTPSession implements Runnable {
private Socket mSocket = null;
public HTTPSession (Socket s) {
mSocket = s;
}
public void run() {
InputStream ips = null;
try {
mSocket.setSoTimeout(15000);
ips = mSocket.getInputStream();
ips.read();
}
catch (Exception e) {
e.printStackTrace();
Log.v("HTTPSession", "Socket connected: " + mSocket.isConnected() + ", Socket closed: " + mSocket.isClosed() + ", InputShutdown: " + mSocket.isInputShutdown());
}
finally {
try { ips.close(); } catch (IOException ioe) { }
try { mSocket.close(); } catch (IOException ioe) { }
}
}
}
So ServerThread accepts the connection, HTTPSession tries to read from the Socket and sometimes it throws the SocketTimeoutException after the 15 seconds are up.
The output from the Log statement in the catch in this case is:
Socket connected: true, Socket closed: false, InputShutDown: false
What gives? Surely 15 seconds is enough of a wait and it seems unlikely that mainstream web browsers just aren't sending any data, so why can't I read it?
I would appreciate any input on this problem.
SocketTimeoutException only means one thing: no data was available within the timeout period. So yes maybe your timeout is too short, and yes the browser didn't send it within the timeout period, or at least it didn't arrive at the server's socket receive buffer within the timeout period.
I would say 15 seconds is a bit aggressive for a server side timeout. 30s to a couple of minutes would be more like it.
I don't see any reason this code would fail in that way unless, like you said, a browser just wasn't sending anything. You could change the ips.read(); to System.out.println(ips.read()); to be sure of that. If you see a byte show up on stdout, then the browser did send something. My guess would be that in your full code, you're not properly recognizing the end of a request and continuing to wait for more data. After 15 seconds, you'll time out. But that's just a guess. If you post some code that demonstrates the problem, someone might be able to give you a definitive answer.