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.
Related
I need to continuously listen to a remote socket and react on given input.
public void listen(String ip, int port) {
try (
Socket socketListener = new Socket(ip, port);
BufferedReader portReader = new BufferedReader(new InputStreamReader(socketListener.getInputStream()));
) {
while (true) {
while (!portReader.ready()) {
// Wait for next PORT message
}
Logger.log(LogComponent.SOCKET, "Event received");
}
}
}
What am I doing so enormously wrong that the code above is using 100% CPU load?
While debugging I can see that the while-!portreader-loop is the evildoer. But most of the examples I've found are doing it the same way.
EDIT #1
Considering your comments I have following solution right now:
try {
Socket SocketListener = new Socket(ip, port);
BufferedReader portReader =
new BufferedReader(
new InputStreamReader(SocketListener.getInputStream())
);
// We do not use common while(true)-pattern for reading the input.
// Instead, we check for new input 3 times a second.
ScheduledExecutorService executor = Executors.newScheduledThreadPool(10);
executor.scheduleAtFixedRate(() -> {
try {
processInput(portReader);
} catch (IOException e) {
e.printStackTrace();
}
}, 0, 333, TimeUnit.MILLISECONDS);
} catch (Exception exception) {
exception.printStackTrace();
}
And processInput(0) is doing the action now.
This ends in better performance results than using simply Thread.sleep() - though I don't understand why.
When using this approach: Can the code miss some messages from the socket? I mean during the intervals?
Your CPU is busy because it's processing instructions in the while loop.
To avoid it, you should use a function that waits for the socket to be connected. If you are waiting for incoming connection, use Socket.accept(). This will block the thread (i.e. thread won't be scheduled for execution) until connection is established.
Do not use Thread.sleep() as others have suggested. While this does lower the CPU usage somewhat, it will still burn CPU unnecessarily, as well as introduce a latency. This is a bad engineering practice.
Apart from that, you might want to look into non-blocking or asynchronous I/O. See here for more information.
The problem is that your code inside your while(true) is consuming all the CPU. Make a single change like:
public void listen(String ip, int port) {
try (Socket socketListener = new Socket(ip, port);
BufferedReader portReader = new BufferedReader(new InputStreamReader(socketListener.getInputStream()));) {
while (true) {
while (!portReader.ready()) {
// Wait for next PORT message
try {
Thread.sleep(1);
} catch(InterruptedException e) {
//handle InterruptedException
}
}
Logger.log(LogComponent.SOCKET, "Event received");
}
}
}
EDIT: I have corrected the mistake below in the code, by adding a line into the server code
I'm trying to write some socket code that will allow me to send data from one computer to another for a game (which for simplicity's sake, we can think of as tic-tac-toe, not much data needs to be sent, just a couple of numbers). In order to achieve this I have written two classes, Server and Client. At the moment I am testing through the localhost using port 1234, and I am only using one single instance of the program (though the same problem occurs when trying to use two instances).
Firstly here's the code, and then I can go into more depth about the problem, and what testing I've done to attempt to work out what is going wrong:
public class Server
{
private ServerSocket server;
private Socket socket;
private Client socketHandler;
private static final int DEFAULT_PORT = 1234;
public Server() { this(DEFAULT_PORT); }
public Server(int port)
{
Thread thread = new Thread()
{
public void run()
{
try
{
System.out.println("Attempting to Establish Connection");
server = new ServerSocket(port);
socket = server.accept();
socketHandler = new Client(port, socket); //THIS LINE ADDED
System.out.println("Server Online!");
}
catch (Exception e)
{
e.printStackTrace();
}
}
};
thread.setDaemon(true);
thread.start();
}
//ADJUSTED
Client getSocketHandler()
{
return socketHandler;
}
public void kill()
{
try
{
if (socket != null) socket.close();
if (server != null) server.close();
}
catch(IOException e)
{
e.printStackTrace();
}
finally
{
socket = null;
server = null;
}
}
}
public class Client
{
public static final int DEFAULT_PORT = 1234;
public static final String DEFAULT_HOST = "localhost";
private static final String THUMP_THUMP = "thump thump";
private static final int PULSE = 1000;
private int port;
private String ip;
private Socket socket;
private BufferedReader input = null;
private PrintWriter output = null;
boolean closed = true;
String data = "";
public Client() { this(DEFAULT_PORT, DEFAULT_HOST, null); }
public Client(int port) { this(port, DEFAULT_HOST, null); }
public Client(int port, String ip) { this(port, ip, null); }
public Client(int port, Socket server) { this(port, DEFAULT_HOST, server); }
public Client(String ip) { this(DEFAULT_PORT, ip, null); }
public Client(String ip, Socket server) { this(DEFAULT_PORT, ip, server); }
public Client(Socket server) { this(DEFAULT_PORT, DEFAULT_HOST, server); }
public Client(int port, String ip, Socket server)
{
socket = server;
this.ip = ip;
this.port = port;
Thread thread = new Thread()
{
public void run()
{
try
{
initialise(server);
String line;
startHeartbeat();
while (isClosed()) {} //first it is closed, lets wait for it to open before we start waiting for it to close!
System.out.println("We are about to listen!");
while (!isClosed())
{
System.out.println("pre-read"); //this line was used to determine that the code was hanging on the next line
line = input.readLine(); //offending line
System.out.println("post-read"); //this line was used to determine when the block was lifted
if (line != null)// || line != THUMP_THUMP)
{
System.out.println(line);
data += line + "\n";
}
}
System.out.println(data);
kill();
System.out.println("Connection Closed!");
}
catch (SocketException e)
{
e.printStackTrace();
System.out.println("Server closed!");
}
catch (Exception e)
{
e.printStackTrace();
}
}
};
thread.setDaemon(true);
thread.start();
}
private void initialise(Socket server)
{
try
{
if (server == null) socket = new Socket(ip, port);
input = new BufferedReader(new InputStreamReader(socket.getInputStream()));
output = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()));
}
catch (IOException e) { e.printStackTrace(); }
}
public boolean post(String text)
{
synchronized(this)
{
output.println(text);
output.flush();
return !output.checkError();
}
}
public void kill()
{
try
{
if (input != null) input.close();
if (socket != null) socket.close();
}
catch(IOException e) { e.printStackTrace(); }
finally
{
input = null;
socket = null;
}
}
public void killOutputStream()
{
try
{
if (output != null) output.close();
}
catch (Exception e) { e.printStackTrace(); }
finally
{
output = null;
}
}
//////////////////////////////////
///////// Socket Control /////////
//////////////////////////////////
synchronized boolean isClosed()
{
return closed;
}
synchronized void setClosed(boolean b)
{
closed = b;
}
//We need to make sure that the socket is still online, to ensure the reading stops when the connection closes.
void startHeartbeat()
{
Thread heartbeat = new Thread()
{
public void run()
{
while (output != null)
{
setClosed(post(THUMP_THUMP) ? false : true); //post returns true on success
synchronized(this)
{
try
{
this.wait(PULSE);
}
catch (InterruptedException e) {}
}
}
setClosed(true);
}
};
heartbeat.setDaemon(true);
heartbeat.start();
}
}
The Problem
When the client is started (after having created the server) it fails to read any data sent through (or even the heartbeat), in fact the code does not go past line = input.readLine() in the reading thread (which is from now on called the offending line), except it seems, until the server is disconnected (see below).
Here is the order of regular testing:
Server() is called and the resulting Server is stored in the serverConnection variable then
Client(serverConnection != null ? serverConnection.getSocket() : null) is called and the new Client is stored in clientConnection.
Because we can test whether it is working using the heartbeat no other data needs to be sent, and the server is terminated by calling serverConnection.kill() and then clientConnection.killOutputStream() after letting some time elapse.
and this is the result:
Attempting to Establish Connection Server Online!
We are about to listen!
Connection Closed!
where the empty line represents the non null data received over the course of the connection, ie that there is none.
I expect this:
Attempting to Establish Connection
Server Online!
We are about to listen!
thump thump
thump thump
thump thump (and so on, every second)
Connection closed!
I spent time performing different tests by commenting out or changing the code slightly with the same testing format (except for the special case, which is number 6) and made these observations:
Observations
Only when the socket is closed and the output stream is closed, does the program move past the offending line.
When the readline() method starts to process (shortly before the heartbeat cuts it off) it detects nothing in the stream, not even THUMP_THUMP.
When the socket is closed, but the output stream is not, the readline() method starts to process, only to detect nothing, heartbeat cuts it off. No SocketException even though it would be expected.
If the socket is NOT closed, and only the output stream is closed, a SocketException is triggered, suggesting the socket is closed.
I used netstat -an in command prompt, and when the server is started the port 1234 is LISTENING. When the client connects, it is still LISTENING, implying that there is no connection.
I set up some python code to connect to itself over port 1234,
however I made a mistake in the python code, and as such the server
didn't close, and was still open. So I decided to connect the java
client to the server and see what happens. I did this by running
Client(null) which is the client code for the non-host. It
resulted in the port reading ESTABLISHED, and the python server was
echoing back the "thump thump", and the java code was successfully
reading it. No hanging, it worked perfectly.
This leads me to believe that the problem lies in the server code, as the python server was able to communicate sucessfully with the Java client, but the Java client is unable to communicate with the Java server.
Before performing this testing I had been concentrating on the Client code, believing that it was at fault. All the questions I have found here with similar symptoms (see here, here and here, among others) have turned up blank for me, having written in their solutions (most were due to the output stream not flushing, or the \n ommitted, which I have not failed to do, or the solution not fixing my problem, and so having been removed in favor of the heartbeat in this case). I originally based my code off of this article.
After 4 days of trying to figure out this problem I am at a loss for what to do... What am I missing here? Why is the Server code not working as I expect it to? If anybody needs any more clarification on my code then please ask!
As an after-note, the testing code is run through a simple minimalistic GUI written in javafx (not fxml though), whether that would be a problem or not I'm sure, I would think not, due to it working with the Python server. This code is compiled in Java 8
I'm a little confused about why you think it would go any furthur than input.readLine() considering there is no handling of inputs/outputs on the server side....
Client/Server connections are like a game of tennis, as one side serves the other must receive the ball and then serve it back(maybe with different information). Your server side must handle the input it recieves from the start heartbeat method, and then send you back a response. the input.readLine() function blocks the thread until it receives data from the other end, so yes the code stops there and waits for your server to send the "tennis ball" back. In the server class you should add an input and output stream that handle the heart beat inputs and send back a string of data to the client.
Server:
OutputStream os = socket.getOutputStream();
InputStream is = socket.getInputStream();
String response = "thump thump";
while(true){
is.read();
os.write(response.getBytes());
os.flush();
}
with this example, the client should remain unchanged and just add the above code to your server.
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'm trying to use server sockets to set up a connection between a client and a server. I'm also not using java.nio.
The problem is that I'm constantly sending a test message, and detecting whether if it is successful in sending the message (the client is still connected), if not, then the client is disconnected.
Shown here:
try
{
Scanner in = new Scanner(socket.getInputStream());
BufferedReader in_2 = new BufferedReader(new InputStreamReader(socket.getInputStream()));
while(stopThread)
{
if(in_2.ready())
{
String message = in_2.readLine();
dt = new DateTime();
PrintStream out = new PrintStream(socket.getOutputStream());
server.detect(message, dataSets, out);
dataSets.add(message);
GUI.textArea_1.append(message + "\r\n");
GUI.textArea_1.setCaretPosition(GUI.textArea_1.getDocument().getLength());
}
else
{
PrintStream out = new PrintStream(socket.getOutputStream());
out.println("Testing Connection \r\n");
if(out.checkError())
{
try
{
socket.close();
}
catch (IOException e)
{
e.printStackTrace();
}
stopThread = false;
GUI.textArea.append(userName + " disconnected \r\n");
GUI.textArea.setCaretPosition(GUI.textArea.getDocument().getLength());
server.inputDataForm(userName, dt, dataSets);
}
Thread.sleep(3000);
}
}
The problem is that the Thread.sleep(3000) is actually interfering with getting data, since after 3 seconds, I will get a huge amount of data (because I stopped the thread for 3 seconds).
Now, what I proposed is a anonymous class in the else statement.
class runThread implements runnable
{
void run()
{
//Put the else statement here
}
}
But the stopThread = false is not a constant, which I'm trying to control.
Other threads I've searched only puts variables inside main inside the anonymous class, but I need stopThread to stop the while loop if the client is disconnected.
Does anyone have an idea?
Thanks!
Consider setting a short timeout on your socket. This will allow you to control how long your thread will block while waiting for data from the socket.
If data are not quickly available, a very specific java.net.SocketTimeoutException will be raised. You can handle this exception by checking your stopThread flag. If it is set, you can return from the method. Otherwise, the socket is still valid and you can try another read operation with timeout.
If any other exception type is thrown, your socket is probably no longer valid.
socket.setSoTimeout(20); /* 1/50th of a second. */
BufferedReader in = new BufferedReader
(new InputStreamReader(socket.getInputStream(), StandardCharsets.UTF_8));
while (!stop) {
try {
String message = in.readLine();
if (message == null)
handleEOF();
else
handleMessage(message);
} catch(SocketTimeoutException ignore) {
/* Loop back to check "stop" flag. */
continue;
} catch(IOException ex) {
handleDisconnection();
break;
}
}
By the way, if you are using Swing, remember that you can only modify graphical components from Swing's Event Dispatch Thread, and you can't tie up the EDT in long-running operations like this socket handling. You should be passing tasks from this thread to Swing's invokeLater() utility.
Why don't you make a class that implements runnable but also has the method stop();
public class MyRunner implements Runnable(){
MutableBoolean stop = false;
public void run(){...}
public void stop(){
stop = true;
}
}
I'm trying to create a server to send a message which is based on the calculation result from another class.
My question is that since the calculation result is from another class, how do I make the server pause till the result is ready, and how should I pass the result to my server class and send out the result?
public class MyServer {
ServerSocket providerSocket;
Socket connection = null;
static ObjectOutputStream out;
ObjectInputStream in;
String message;
public static String myServerSend;
BufferedReader data = new BufferedReader(data);
MyServer() {}
void run() {
try {
providerSocket = new ServerSocket(2013, 10);
System.out.println("Waiting for connection");
connection = providerSocket.accept();
out = new ObjectOutputStream(connection.getOutputStream());
out.flush();
in = new ObjectInputStream(connection.getInputStream());
do {
try {
message = (String) in.readObject();
System.out.println("server receive>" + message);
// HERE IS MY QUESTION
// myServerSend is the result from other class,
//How can I pause the server here till myServerSend is ready???????
sendMessage(myServerSend);
} catch (ClassNotFoundException classnot) {
System.err.println("Data received in unknown format");
}
} while (!message.equals("bye"));
} catch (IOException ioException) {
ioException.printStackTrace();
}
}
//write msg into ObjectOutputStream
public static void sendMessage(String msg) {
try {
out.writeObject(msg);
out.flush();
System.out.println("server send>" + msg);
} catch (IOException ioException) {
ioException.printStackTrace();
}
}
Use
Thread.sleep(30000); // Milli secs - 30 secs -- Put your sleep time
sendMessage(myServerSend);
Without more specific info about what you have tried and why you have discarded what you have tried, I see several options here.
Call directly the other class and wait till the result is ready. This may not be a good idea if the calculation takes too long, but if not, it's the simplest way.
You can apply polling and get the server to sleep for a certain amount of time to not exhaust resources while waiting for an answer.
Use synchronized objects and concurrency via wait and notify methods. Some useful links on this: 1 2 3
You have few options to acheive this:
1- Create a Thread for your calculation and call join to make your server wait for the thread to finish
Thread thread = new Thread() {
public void run(){
// Call your calculation class
}
}
thread.start();
thread.join(); // surround with try and catch
// or you can use to timeout if the calculation took long
// thread.join(MAX_TIME_MILLIS);
sendMessage(myServerSend);
2- Use wait/notify on a shared object between your server and calculation class
3- Use semaphore object initialized with 0 and call acquire in your server class to wait and call release after you finish your calculations, see my answer here for an example