If I kill the Socket Server process, my Socket client process does not receive any errors, it continues to loop forever on the following code:
public void run() {
while(readData) {
String inputLine = null;
try {
while((inputLine = m_inputStream.readLine()) != null) {
//do stuff
}
} catch (IOException e) {
readData = false;
}
}
}
How can I detect that the socket server is gone and terminate the loop?
Terminate the outer loop when the call to readLine() returns null.
No exception is thrown when the server closes the connection normally. The stream should return null to signal the end of data.
This can be done with a loop like this:
public void run() {
try {
while (true) {
String line = input.readLine();
if (line == null)
break;
/* Process line. */
...
}
} catch (IOException ex) {
/* Handle the exception as desired. */
ex.printStackTrace();
}
}
Whilst the answer from erickson is correct, have you tried setting the socket read time-out properties? (e.g. sun.net.client.defaultReadTimeout). If it is possible that the server may take a long time responding, then this might be less useful as a solution to your problem but is a good idea nevertheless in many scenarios.
Related
This question already has answers here:
Java socket API: How to tell if a connection has been closed?
(9 answers)
Closed 5 years ago.
I'm trying to find a way to see when a client that is connected to my server has disconnected. The general structure of my code is like this, I have omitted irrelevant sections of my code:
public class Server {
public static void main(String[] args) {
...
try {
ServerSocket socket = new ServerSocket(port);
while (true) {
// wait for connection
Socket connection = socket.accept();
// create client socket and start
Clients c = new Server().new Clients(connection);
c.start();
System.out.printf("A client with IP %s has connected.\n",c.ip.substring(1) );
}
} catch (IOException exception) {
System.out.println("Error: " + exception);
}
}
class Clients extends Thread {
...
public Clients(Socket socket) {
clientSocket = socket;
ip=clientSocket.getRemoteSocketAddress().toString();
try {
client_in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
client_out = new PrintWriter(clientSocket.getOutputStream(), true);
} catch (IOException e) {
//error
}
}
public void run() {
...
try {
while (true) {
while ((message = client_in.readLine()) != null) {
...
}
}
} catch (IOException exception) {
System.out.printf("Client with IP %s has disconnected.\n" , ip.substring(1));
}
}
}
}
Basically what I'm trying at the moment is detecting the disconnection through the catch statement in run(), but the issue with this is it doesn't display the message until I terminate my server.
I have also tried to put my print statement after the while(true) loop but my IDE tells me that code is unreachable.
Is there a way to get my "Client with IP %s has disconnected." to display as soon as the client connection is disconnected? What and where should I be checking?
what I'm trying to do is detecting the disconnection through the catch statement.
Bzzt. readLine() doesn't throw an exception at end of stream. It returns null. Any exception you catch here is an error, and should be reported as such.
while (true) {
while ((message = client_in.readLine()) != null) {
...
}
The problem is here. You are detecting when the peer disconnects: readLine() returns null and terminates the inner loop. However you have pointlessly enclosed the correct inner read loop in an outer while (true) loop, which by definition can never exit.
Remove the outer loop.
I tried everything stack overflow has to offer on this common readLine problem. (sending \n, flushing out, changing to byte array style, becoming hermit, wrists )
I suspect in this case its a concurrency thing as Ispent well over 15 hours yesterday confirming that the only thing that isnt working is readline()!
I used loads of other versions like datareader with a byte array and making sure a \n got sent I even sent /ns just in case!
still my issue is the same, and I have ran out of ideas myself to solve the issue and have decided that somewhere, my problem is outside my understanding, just where? its got to be threading right?
I managed to get to read the socket to string that seemed to work so it IS blocking because reading the connection isnt working at all, the readline function is not the only way Ive had it as I said so in my snippets its not as developed as it has been but still the basic issue remains.
Please help, i dont know what the issue is
// So the main class initialises the socket objects and starts them in a thread, these work I get all sorts of flags letting me know that they are
void start_sockets() {
//if this is initiialised as a server and not a client
if (is_server) {
while (is_server) {
try {
System.out.println("listening for connection");
Sockject sj = new Sockject(server.accept());
sock_arr.add(sj);
System.out.println("server made connection ");
// once the connection is made the objects is started in a
// separate thread
new Thread(sock_arr.get(sock_arr.size() - 1)).start();
} catch (IOException e) {
}
}
} else { //else im running a client version of this class
// if the client socket isnt running in a thread, make it run
if (!running) {
new Thread(sj_client).start();
if (sj_client.sock.isConnected()) {
System.out.println("client thread connected to "
+ sj_client.sock.getLocalSocketAddress());
running = true;
}
}
}
}
//the inner class creates a socket object and puts it on an array or an object depending if the parent class is initialised to be a server or a client
class Sockject implements Runnable {
PrintWriter out;
BufferedReader in;
// a socket for processing
Socket sock;
// the constructor in this case initialises the input and output streams
Sockject(Socket s) {
sock = s;
try {
out = new PrintWriter(sock.getOutputStream());
in = new BufferedReader(new InputStreamReader(
this.sock.getInputStream()));
} catch (IOException e) {
close sockets
}
}
//tried variasions of this and similar, used data objects and been sennding /ns all over the shop
void recieve_data() throws IOException {
if (sock.isConnected()) {
if ((recieve = in.readLine()) != null) {
System.out.println("recieve says " + recieve);
}
}
}
// sends data to connection if it is cleared to send data
void send_data(String data) {
// send data called
if (clear_to_send == true) {
out.print(data);
out.flush();
clear_to_send = false;
}
}
#Override
public void run() {
while (threadloop ) {
try {
//code defo gets this far and with just send it keeps running forever so its defo recieve data thats the issue
send_data(send);
recieve_data();// <---I HATE YOU
} catch (IOException e) {
}
}
}
}
}
Now all of the above is ran in an instance of this class, in a thread of this class here these temporary functions are ran and are neversuccesfull
void servrecievex(){
System.out.println("NEVER GETS THIS FA THOUGH DOES IT");
for(int a = 0; a < net_flow.sock_arr.size(); a++){
if(net_flow.sock_arr.get(a).sock.isConnected()){
System.out.println("server recieve function");
net_flow.sj_client.clear_to_send = true;
net_flow.sock_arr.get(a).send_data("www /n \n");
System.out.println("RECIVEIFY!!!");
}
}
}
void clientsendx() {
net_flow.sj_client.clear_to_send = true;
net_flow.sj_client.send_data(Integer.toString(player1.posx) + "\n");
System.out.println("client sent stuff");
}
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 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.