Interrupt/stop thread with socket I/O blocking operation - java

At some point of my server application I want to stop some threads that are performing I/O blocking operations.
For instance, one of them have the following run() method:
public void run() {
System.out.println("GWsocket thread running");
int len;
byte [] buffer = new byte[1500];
try {
this.in = new DataInputStream(this.socket.getInputStream());
this.out = new DataOutputStream(this.socket.getOutputStream());
running = true;
while (running){
len = in.read (buffer);
if (len < 0)
running = false;
else
parsepacket (buffer, len);
}
}catch (IOException ex) {
System.out.println("GWsocket catch IOException: "+ex);
}finally{
try {
System.out.println("Closing GWsocket");
fireSocketClosure();
in.close();
out.close();
socket.close();
}catch (IOException ex) {
System.out.println("GWsocket finally IOException: "+ex);
}
}
}
If I Want to stop a thread running this code, what should I do?
Here they show how to do (How do I stop a thread that waits for long periods (e.g., for input)?), but I don't understand what they mean with:
For this technique to work, it's critical that any method that catches
an interrupt exception and is not prepared to deal with it immediately
reasserts the exception. We say reasserts rather than rethrows,
because it is not always possible to rethrow the exception. If the
method that catches the InterruptedException is not declared to throw
this (checked) exception, then it should "reinterrupt itself" with the
following incantation: Thread.currentThread().interrupt();
Can anyone give me some hints? Some code examples would be very appreciated.

A solution, described by Peter Lawrey and also seen here is to close the socket.
With nio, You could also use a SocketChannel which is interruptible and would allow the application of the standard interrupt model of Java.
A call to the interrupt method of your Thread object would throw an InterruptedException which would stop even your blocking IO operation.

You can add a method like
public void close() throws IOException {
this.socket.close();
}
and any blocking IO operations will throw a SocketException.
You might like to set a flag like closed which you can check if an exception thrown was to be expected or not.
BTW: You cannot be sure that you will get discrete packets on a read. It is far better to read what you need and use BufferedInputStream for efficiency. Only read blocks if you don't need to parse the contents e.g. copying from a socket to a file.
e.g. your read could get just one byte or get the end of one packet and the start of another.

Related

Android socket connects but cant write to it

I was trying to get some networking going in my app, but i encountered some issues. It seems that I cant write to the OutputStream object. Though my server recieves the connection, it does not recieve any data. I've tried using Writer, DataOutputStream among others. none seemed to work.
My app uses asynctasks that call this object with a Socket object and a message. (The socket object has already been used to set Streams after initialisation using the setStreams method.)
can someone please try and find the problem? I will be very thankful.
public class NetworkingUtils {
private OutputStream out = null;
private InputStream in = null;
//set streams
public void setStreams(Socket sock){
if (sock.isConnected()) {
try {
this.out = (OutputStream) sock.getOutputStream();
this.in = (InputStream) sock.getInputStream();
} catch (Throwable e) {
Log.d("SOCKET", "FAILED TO SET STREAMS");
e.printStackTrace();
}
}
}
//send \n terminated messages to pre defined socket
public void sendMessage(Socket sock, String message) throws Throwable {
if (sock.isConnected()) {
try {
this.out.write(message.getBytes());
Log.d("SOCKET","WRITING COMPLETE. " + message);
} catch (Throwable e) {
throw e;
}
}
}
public String recvMessage(Socket sock) throws Throwable {
//receives \n terminated message from pre defined socket
String answer = null;
if (sock.isConnected()){
try{
answer = this.convertStreamToString(this.in);
Log.d("SOCKET","READING COMPLETE");
}
catch (Throwable e){
Log.d("socket",e.getLocalizedMessage());
throw e;
}
}
else{
Log.d("socket","is not connected!!!");
}
if (answer.length() == 0){
//empty string answer from server
throw new IOException();
}
else {
return answer;
}
}
private String convertStreamToString(java.io.InputStream is) {
java.util.Scanner s = null;
try{
s = new java.util.Scanner(is).useDelimiter("\r\n");}
catch (Throwable e){
e.printStackTrace();
}
return s.hasNext() ? s.next() : "";
}
}
I can only see one client-side that might cause this ... and I'm doubtful about it. (That is to say: try this, just in case it makes a differences, but I don't think it will.)
this.out.write(message.getBytes());
Log.d("SOCKET","WRITING COMPLETE. " + message);
The potential problem is that if out is a "buffered" stream, then a write may only result in the bytes being written to the buffer. It may be necessary to call this.out.flush() to "push" to the server.
But I am doubtful it will help, because (to my knowledge) a socket output stream isn't buffered in Java. I think it is more likely that the real problem is on the server side.
If you are stumped with figuring out which side the problem is occuring, I suggest you try using a network monitoring / packet sniffing tool (on the server side) to check if the data is reaching the server host.
While I have your attention, your exception code is really, really bad.
Don't declare methods as throws Throwable (or throws Exception). That basically says "this method may throw ANY exception, and I'm not telling you which one". When you do that, the caller code has to cope with any exception, which is basically impossible to do intelligently.
What you should do is to declare the method as throwing the checked exceptions that the code can throw. For example, in your case, IOException is probably sufficient.
It is not a good idea to catch an exception, log it, and then rethrow it. Why? Because further up the stack there are probably other methods that will see the exception. They can't know if the exception has already been logged or not. So should they log it (possibly resulting in duplicate logs events for the same problem) or not (possibly resulting in the exception going unlogged.)
Don't throw exceptions without a message:
throw new IOException();
It is lazy. You should always include a simple message that can (at least) be grep'd or googled for.
In addition, your testing of Socket.isConnected() all over the place is unnecessary. According to the javadoc:
Returns: true if the socket was successfuly connected to a server
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.
So repeatedly testing isConnected is nugatory. If it returns true once, it will will always return true from then on.
Even the initial isConnected test in setStreams is doubtful. I'd just call getInputStream without testing, and rely on the Socket API throwing an IOException if the socket is in the wrong state.
You're effectively reading lines with that obscure Scanner usage, but you're not writing lines. So the scanner will block until a line terminator or EOS arrives.
You need to append a line terminator when sending.

java socket Object memory leak

i've a memory leak problem on java Socket Object communication.
this is my send thread.
// create a new thread to send the packet
#Override
public synchronized void run() {
if(!genericSocket.isConnected()){
if(logger.isEnabled())
logger.logMessage(PFLogging.LEVEL_WARN, "Socket is close");
return;
}
int retry = 0;
boolean packetSent = false;
synchronized (objWriter) {
while ((retry < RETRY) && (!packetSent) && (genericSocket.isConnected())) {
try {
objWriter.writeObject(bean);
objWriter.flush();
// Try until the cache is reset and the memory is free
/*
boolean resetDone = false;
while(!resetDone) {
try {
objWriter.reset();
resetDone = true;
} catch (IOException r) {
Thread.sleep(1);
}
}
*/
// No error and packet sent
continuousError = 0;
packetSent = true;
} catch (Exception e) {
continuousError++;
if(logger.isEnabled())
logger.logMessage(PFLogging.LEVEL_ERROR, "Continuous Error [" + continuousError + "] sending message [" + e.getMessage() + "," + e.getCause() + "]");
// control the number of continuous errors
if(continuousError >= CONTINUOUS_ERROR) {
if(logger.isEnabled())
logger.logMessage(PFLogging.LEVEL_WARN, "I close the socket");
genericSocket.disconnect();
}
// next time is the time!
retry++;
}
}
}
}
the cache, when i sent about i packet per ms grow and grow!
if i add the commented part the cache is clean but when i need to send an async long message (about 3000 char) i see that the other message are lost!
There's another way to clean the cache without reset it??
ObjectOutputStream.reset() is not avoidable as it is the only means of clearing local hash tables, you can refer java source code for ObjectOutputStream for details of what happens in reset(), or else you will get OutOfMemoryError eventually
But you can very well implement a function like
private void writeObject(Object obj, ObjectOutputStream oos) throws IOException
{
synchronized(oos)
{
oos.writeObject(obj);
oos.flush();
oos.reset();
}
}
However you must ensure that all writes to ObjectOutputStream happens through this method.
the only solution i find is, first of starting a sending thread, to check if the thread pool is empty and in that case i reset the output stream.
I run the software all this night to check this.
Thanks all!
Matteo
I would use ObjectOutputStream.reset() periodically to clear the object cache for the stream.
You could even use it after sending every object. ;)
ciao :),
after ObjectOutputStream.flush() you can saftely use ObjectOutputStream.reset()
unless you are using the objWriter somwhere in another thread without using the synchronized (objWriter) statement.
In this case the best way IMHO is to use the objWriter in a thread, it will send object from a syncornized queue (see Queue sub-class http://docs.oracle.com/javase/1.5.0/docs/api/java/util/Queue.html, for example http://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/ConcurrentLinkedQueue.html) that is filled from the other thread (remeber to use object.clone(), because the objcet itself isn't syncornized it can be modified by other thread while you are writing it or is in queue! if you clone it your clone will be a safe copy).
That way you don't need synchronized statment because data-flow between thread and ObjectOutputStream is already synchronized, and you will be less error-prone

Killing a thread after socket closed

I wanna kill the TCP connection listener thread(serverside) after client closes the socket..
The thread waits in the loop in the readLine()..
How can i do it?
while(isconnected){
String msg = in.readLine();
//..
}
You have to call socket.close() method, if you are using it properly it should be fine. I don't know where readLine() is coming from, so I will assume its BufferedReader. If you look here in the documentation BufferedReader readLine()
you will see that it throws IOException if there is an error and if it is end of stream it will return null.
so you should basically do this:
try{
while(socket.isConnected()){
String line = in.readLine();
if(line==null){
//END OF STREAM
}
}
}catch(IOException e){
//deal with IOException here
}
otherwise, what I assume your currently doing is sitting in a tight loop as soon as the other end disconnects. If you try too print out msg in your above code you will see it print out null nonstop.
Perhaps extend your protocol so that the client sends a QUIT message before closing its socket.
First, you can't tell if the client is just taking a long time to respond, or if it is down.
What you can do is set some timeout period and have a thread in the server that calls clientSocket.close() after the timeout has elapsed. This will throw a SocketException in the receiving thread. It will take you out of the receiving loop and the thread will just terminate by itself if there is nothing after the receiving loop.
WalterM is basically right. The readLine call will return null is the stream is closed by the remote client, and will throw an exception if the connection "breaks" without a proper close, or the low-level socket read times out.
It is worth pointing out that it is simpler and more efficient to just do this:
try {
String msg;
while ((msg = in.readLine()) != null) {
// do stuff
}
} catch (IOException ex)
// report error
} finally {
// Close the socket under all circumstances to avoid potential
// resource leakage
try {
socket.close();
} catch (IOException ex) {
// ignore
}
}
Checking that the socket is still connected it redundant. The low-level socket read will be doing that anyway.
You'll need to interrupt the thread.

How to interrupt BufferedReader's readLine

I am trying to read input from a socket line by line in multiple threads. How can I interrupt readLine() so that I can gracefully stop the thread that it's blocking?
EDIT (bounty): Can this be done without closing the socket?
Without closing the socket:
The difficult problem isn't the BufferedReader.readLine, but the underlying read. If a thread is blocked reading, the only way to get it going is to supply some actual data or close the socket (interrupting the thread probably should work, but in practice does not).
So the obvious solution is to have two threads. One that reads the raw data, and will remain blocked. The second, will be the thread calling readLine. Pipe data from the first the second. You then have access to a lock than can be used to wakeup the second thread, and have it take appropriate action.
There are variations. You could have the first thread using NIO, with a single thread instance shared between all consumers.
Alternatively you could write a readLine that works with NIO. This could even take a a relatively simple single-threaded form, as Selector.wakeup exists and works.
Close the socket on the interrupting thread. This will cause an exception to be thrown on the interrupted thread.
For more information on this and other concurrency issues, I highly recommend Brian Goetz's book "Java Concurrency in Practice".
Sorry for being over 6 years late ;-) I had a need for some interruptible readLine when reading from the keyboard, for a simple hobby console application. In other words, I couldn't "close the socket".
As you may know, System.in is an InputStream that apparently already does some buffering (you need to press Enter]). However, it seems to be suggested to wrap it in a BufferedReader for better efficiency, so my input is from:
BufferedReader consoleIn = new BufferedReader(new InputStreamReader(System.in));
The other thing one might have discovered is that BufferedReader.readLine() blocks until input is provided (even if the thread is interrupted, which seems to only end the thread once readline() gets its input). It is however possible to predict when BufferedReader.read() will not block, by calling BufferedReader.ready() == true. (However, == false does not guarantee a block, so beware.)
So I have incorporated the above ideas into a method that reads the BufferedReader character by character, checking in between each character if the thread has been interrupted, and also checks for end-of-line, at which point the line of text is returned.
You may find this code useful, pass the consoleIn variable as declared above. (Criticism may be welcomed too...):
private String interruptibleReadLine(BufferedReader reader)
throws InterruptedException, IOException {
Pattern line = Pattern.compile("^(.*)\\R");
Matcher matcher;
boolean interrupted = false;
StringBuilder result = new StringBuilder();
int chr = -1;
do {
if (reader.ready()) chr = reader.read();
if (chr > -1) result.append((char) chr);
matcher = line.matcher(result.toString());
interrupted = Thread.interrupted(); // resets flag, call only once
} while (!interrupted && !matcher.matches());
if (interrupted) throw new InterruptedException();
return (matcher.matches() ? matcher.group(1) : "");
}
... And in the thread that is calling this, catch the exceptions and end the thread appropriately.
This was tested in Java 8 on Linux.
I was playing around with this recently (using Scala), and I didn't like the accepted answer of closing the socket and getting an exception.
Eventually I discovered that it's possible to call socket.shutdownInput() in the interrupting thread to get out of the readLine call without an exception. I make this call in a SIGINT handler so that I can clean up and close the socket in the main thread.
Note, that the equivalent exists for the outputstream with socket.shutdownOutput()
you can design a Timer class around the read() block.
you need to set a timeout for your timer.
on timeout just interrupt your thread.
Without closing the socket, no question the best solution with the least overhead is to simply avoid using the blocking read methods until the BufferedReader is ready, or a timeout is reached.
public String readLineTimeout(BufferedReader reader, long timeout) throws TimeoutException, IOException {
long start = System.currentTimeMillis();
while (!reader.ready()) {
if (System.currentTimeMillis() - start >= timeout)
throw new TimeoutException();
// optional delay between polling
try { Thread.sleep(50); } catch (Exception ignore) {}
}
return reader.readLine(); // won't block since reader is ready
}
If you want to use readLine on a server socket within a client-server tcp architecture, for instance, you can use setSoTimeout(int timeout) of java.net.Socket.
From the Socket#setSoTimeout(int timeout) Documentation:
Enable/disable SO_TIMEOUT with the specified timeout, in milliseconds. With this option set to a non-zero timeout, a read() call on the InputStream associated with this Socket will block for only this amount of time. If the timeout expires, a java.net.SocketTimeoutException is raised, though the Socket is still valid.
public class MainApp {
public static void main(String[] args) throws Exception {
ExecutorService executorService = Executors.newFixedThreadPool(10);
ServerSocket serverSocket = new ServerSocket(11370);
Socket clientSocket = serverSocket.accept();
clientSocket.setSoTimeout(2000);
executorService.execute(new ReadingThread(clientSocket));
// ... some async operations
executorService.shutdown();
}
}
public class ReadingThread implements Runnable {
private final Socket clientSocket;
public ReadingThread(Socket clientSocket) {
this.clientSocket = clientSocket;
}
#Override
public void run() {
BufferedReader socketReader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
String readInput = null;
while (!Thread.currentThread().isInterrupted()) {
try {
readInput = socketReader.readLine();
} catch (SocketTimeoutException e) {
continue;
}
}
// operations with readInput
}
}
The main application implements a server socket which listens to connections and has a thread pool. If an incoming client communication is accepted, then a new Thread from the pool is assigned and the run function is invoked in ReadingThread (can be adjusted to allow multiple threads).
On the socket used for communicating to the client the property setSoTimeout(int timeout) has been set. Therefore if readLine does not return within the specified timeout a SocketTimeoutException is thrown.
You can check in a loop whether the ReadingThread has been interrupted by the main application, and if so stop reading from the socket.
When the buffered reader is being used to read the input stream from a socket then you can achieve this by having the read call timeout. Once this timeout is triggered you will be able to check if your thread should be stopped. To do this call setSoTimeout on the socket. The read call will then have a SocketTimeoutException and you can use that to stop the thread.
#Override
public void run() {
running = true;
try {
socket.setSoTimeout(1000); // This will determine how quick your thread responds to the shutdown call
var inputStream = socket.getInputStream();
bufferedReader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
} catch (IOException e) {
Logger.error("IOException while setting up input stream");
Logger.error(e);
return;
}
StringBuilder stringBuilder = null;
while (running) {
try {
int singleChar = bufferedReader.read();
// Do something with the data
} catch (SocketTimeoutException e) {
// SocketTimeoutException is expected periodically as we do setSoTimeout on the socket,
// this makes the above read call not block for ever and allows the loop to be interrupted
// cleanly when we want to shut the thread down.
Logger.trace("Socket timeout exception");
Logger.trace(e);
} catch (IOException e) {
Logger.error("IOException while reading from socket stream");
Logger.error(e);
return;
}
}
}
public void stopThread() {
running = false;
try {
bufferedReader.close();
} catch (IOException e) {
Logger.error("IOException while closing BufferedReader in SocketThread");
Logger.error(e);
}
}
Answer found here: Any way of using java.nio.* to interrupt a InputStream#read() without closing socket?
I think that you might have to use something other than readLine(). You could use read() and at every loop iteration check to see if the thread was interrupted and break out of the loop if it was.
BufferedReader reader = //...
int c;
while ((c = reader.read()) != -1){
if (Thread.isInterrupted()){
break;
}
if (c == '\n'){
//newline
}
//...
}
A sketch for a solution might be this: NIO provides methods for nonblocking IO, so you have to implement something called Foo that uses nonblocking NIO on the socket end but also provides a InputStream or Reader interface on the other end. If the BufferedReader enters its own read, it will call Foo, which will call Selector.select with read intent. select will either return indicating the presence of more data or it will block until more data is available.
If another thread wants to unblock the reader, it must call Selector.wakeup and the selector can return gracefully by throwing an exception the by BufferedReader.
The socket should be still open after that.
Variation A: call Selector.select(timeout) to do busy polling light.

Strange Java Socket Behavior (Connects, but Doesn't Send)

I have a fairly complex project that boils down to a simple Client / Server communicating through object streams.
Everything works flawlessly for two consecutive connections (I connect once, work, disconnect, then connect again, work, and disconnect). The client connects, does its business, and then closes. The server successfully closes both the object output stream and the socket, with no IO errors.
When I try to connect a third time, the connection appears to go through (the ServerSocket.accept() method goes through and an ObjectOutputStream is successfully created). No data is passed, however. The inputStream.readUnshared() method simply blocks.
I have taken the following memory precautions:
When it comes time to close the sockets, all running threads are stopped, and all objects are nulled out.
After every writeUnshared() method
call, the ObjectOutputBuffer is
flushed and reset.
Has anyone encountered a similar problem, or does anyone have any suggestions? I'm afraid my project is rather large, and so copying code is problematic.
The project boils down to this:
SERVER MAIN
ServerSocket serverSocket = new ServerSocket(port);
while (true) {
new WorkThread(serverSocket.accept()).start();
}
WORK THREAD (SERVER)
public void run() {
ObjectInputBuffer inputBuffer = new ObjectInputBuffer(new BufferedInputStream(socket.getInputStream()));
while (running) {
try {
Object myObject = inputBuffer.readUnshared();
// do work is not specified in this sample
doWork(myObject);
} catch (IOException e) {
running = false;
}
}
try {
inputBuffer.close();
socket.close();
} catch (Exception e) {
System.out.println("Could not close.");
}
}
CLIENT
public Client() {
Object myObject;
Socket mySocket = new Socket(address, port);
try {
ObjectOutputBuffer output = new ObjectOutputBuffer(new BufferedOutputStream(mySocket.getOutputStream()));
output.reset();
output.flush();
} catch (Exception e) {
System.out.println("Could not get an input.");
mySocket.close();
return;
}
// get object data is not specified in this sample. it simply returns a serializable object
myObject = getObjectData();
while (myObject != null) {
try {
output.writeUnshared(myObject);
output.reset();
output.flush();
} catch (Exception e) {
e.printStackTrace();
break;
} // catch
} // while
try {
output.close();
socket.close();
} catch (Exception e) {
System.out.println("Could not close.");
}
}
Thank you to everyone who may be able to help!
(1) What's ObjectInputBuffer and ObjectOutputBuffer? Did you mean ObjectInputStream & ObjectOutputStream?
(2) If so, calling reset() immediately after creating the ObjectOutputStream is just a waste of time and bandwidth.
(3) Why are you printing 'could not get an input' on an exception creating an output stream?
(4) When you get an exception you should always print its message - don't completely substitute it with your own, that's just throwing away useful information.
(5) You are assuming that any IOException when reading means the end of the stream. Only EOFException means that. Any other IOException should be printed or logged. Clearly you are getting some other exception here and ignoring it.
(6) Why do you keep sending the same object?
From ObjectInputStream API for readUnshared():
Reads an "unshared" object from the
ObjectInputStream. This method is
identical to readObject, except that
it prevents subsequent calls to
readObject and readUnshared from
returning additional references to the
deserialized instance obtained via
this call.
Could this be the problem? Use readObject() instead.

Categories

Resources