I'm trying to read items from a socket and I notice that if there is nothing on the stream of the socket it will stay at the read and back up my application. I wanted to know if there was a way to set a read timeout or terminate the connection after a certain amount of time of nothing in the socket.
If you write Java, learning to navigate the API documentation is helpful. In the case of a socket read, you can set the timeout option, e.g.:
socket.setSoTimeout(500);
This will cause the InputStream associated with the socket to throw a SocketTimeoutException after a read() call blocks for one-half second. It's important to note that SocketTimeoutException is unique among exceptions thrown by such read() calls, because the socket is still valid; you can continue to use it. The exception is only a mechanism to escape from the read and decide if it's time to do something different.
while (true) {
int n;
try {
n = input.read(buffer);
catch (SocketTimeoutException ex) {
/* Test if this action has been cancelled */
if (Thread.interrupted()) throw new InterruptedIOException();
}
/* Handle input... */
}
If this socket was created through a URLConnection to perform a web request, you can set the read and connect timeouts directly on the URLConnection before reading the stream:
InputStream createInputStreamForUriString(String uriString) throws IOException, URISyntaxException {
URLConnection in = new URL(uriString).openConnection();
in.setConnectTimeout(5000);
in.setReadTimeout(5000);
in.setAllowUserInteraction(false);
in.setDoInput(true);
in.setDoOutput(false);
return in.getInputStream();
}
Yes, there should be an override of Read() that accepts a timeout value. By 'override' I am not suggesting anyone write one, I am pointing out that one of the overrides of the socket methods he is using takes a timeout value.
Related
Learning about HTTP requests in Java. I'd like to know if reading the response body is essential to keeping a connection alive.
Here's an example code block (which posts a message to some URL):
private void writeToConnection(String url, String msg) throws IOException {
try {
HttpURLConnection connection = open(url);
// "Try with resources"
try (BufferedWriter writer = new BufferedWriter(
new OutputStreamWriter(connection.getOutputStream()))) {
writer.write(msg);
}
// Why do I need this line?
IOUtils.readStringFromStream(connection.getInputStream());
int code = connection.getResponseCode();
System.out.println(String.format("Returned response code %d.", code));
} catch (IOException e) {
e.printStackTrace();
}
}
Why is it necessary to read the input stream? The method readStringFromStream is returning a string but the string is not being assigned to anything. Does this ensure the connection stays alive? If so, how does the connection stay alive when the first line in the method opens a new connection? If the next batch of data to be written invokes this method, wouldn't that discard the old connection and open a new one?
I believe the intent of this code is indeed to consume the response body so that the connection can be reused. However, I'm not sure that this approach is correct; it is also likely to depend on the version of Java you are using.
First, it should suffice to get the connection's InputStream and close it; behind the scenes, the body still needs to be read, but closing the stream signals to the connection handler that the application wants to skip the body, and the handler can read and discard the content before putting the connection into a cache for re-use.
However, depending on the status, there could be an error stream instead of an input stream. Even in this case, the body needs to be consumed before the connection can be re-used, but many applications (like this one) don't bother reading the body of an error message. Since Java 7, however, if the error body is small enough, it will be consumed and buffered automatically.
Behind the scenes, a connection cache is used to retain open connections. Although the method names suggest a new connection is opened every time, in fact the cache is first checked for an open connection.
Explanation
I'm revisiting the project I used to teach myself Java.
In this project I want to be able to stop the server from accepting new clients and then perform a few 'cleanup' operations before exiting the JVM.
In that project I used the following style for a client accept/handle loop:
//Exit loop by changing running to false and waiting up to 2 seconds
ServerSocket serverSocket = new ServerSocket(123);
serverSocket.setSoTimeout(2000);
Socket client;
while (running){ // 'running' is a private static boolean
try{
client = serverSocket.accept();
createComms(client); //Handles Connection in New Thread
} catch (IOException ex){
//Do Nothing
}
}
In this approach a SocketTimeoutException will be thrown every 2 seconds, if there are no clients connecting, and I don't like relying on exceptions for normal operation unless it's necessary.
I've been experimenting with the following style to try and minimise relying on Exceptions for normal operation:
//Exit loop by calling serverSocket.close()
ServerSocket serverSocket = new ServerSocket(123);
Socket client;
try{
while ((client = serverSocket.accept()) != null){
createComms(client); //Handles Connection in New Thread
}
} catch (IOException ex){
//Do Nothing
}
In this case my intention is that an Exception will only be thrown when I call serverSocket.close() or if something goes wrong.
Question
Is there any significant difference in the two approaches, or are they both viable solutions?
I'm totally self-taught so I have no idea if I've re-invented the wheel for no reason or if I've come up something good.
I've been lurking on SO for a while, this is the first time I've not been able to find what I need already.
Please feel free to suggest completely different approaches =3
The problem with second approach is that the server will die if an exception occurs in the while loop.
The first approach is better, though you might want to add logging exceptions using Log4j.
while (running){
try{
client = serverSocket.accept();
createComms(client);
} catch (IOException ex){
// Log errors
LOG.warn(ex,ex);
}
}
Non-blocking IO is what you're looking for. Instead of blocking until a SocketChannel (non-blocking alternative to Socket) is returned, it'll return null if there is currently no connection to accept.
This will allow you to remove the timeout, since nothing will be blocking.
You could also register a Selector, which informs you when there is a connection to accept or when there is data to read. I have a small example of that here, as well as a non-blocking ServerSocket that doesnt use a selector
EDIT: In case something goes wrong with my link, here is the example of non-blocking IO, without a selector, accepting a connection:
class Server {
public static void main(String[] args) throws Exception {
ServerSocketChannel ssc = ServerSocketChannel.open();
ssc.configureBlocking(false);
while(true) {
SocketChannel sc = ssc.accept();
if(sc != null) {
//handle channel
}
}
}
}
The second approach is better (for the reasons you mentioned: relying on exceptions in normal program flow is not a good practise) allthough your code suggests that serverSocket.accept() can return null, which it can not. The method can throw all kinds of exceptions though (see the api-docs). You might want to catch those exceptions: a server should not go down without a very good reason.
I have been using the second approach with good success, but added some more code to make it more stable/reliable: see my take on it here (unit tests here). One of the 'cleanup' tasks to consider is to give some time to the threads that are handling the client communications so that these threads can finish or properly inform the client the connection will be closed. This prevents situations where the client is not sure if the server completed an important task before the connection was suddenly lost/closed.
Trying to read some image files from a server and using socket programming for the same.
But I am getting socketTimeOut exception when there is no file exist. Not only that loosing the connection to the server.
How can I avoid loosing the connection to the server when there is no file exist.
InputStream inputStream = new BufferedInputStream(socket().getInputStream());
int i = -1;
while ((i = bufferedInputStream.read()) != -1) {
byteArrayOutputStream.write(i);
}
In the above code I am getting exception, when I call read() on bufferedInputStream. How can I handle this exception and loosing connection to server.
Thanks
You don't get that exception 'when the file [doesn't] exist'. You get it when you have set a read timeout and no data has arrived within the timeout, if your timeout is too short, raise it. If you want to wait forever, remove it. It's your timeout, you set it.
If you get a SocketTimeoutException you don't lose the connection. What makes you think you did?
I have scenario in which there is server listening on specified ip and port and client which connects to that server.
Now I am reading response from server using readline method:
String readme=bs.readline()).
Here bs is bufferedreader object. I want to know if before reading response if I write this line
socket.setSoTimeout(1000)
and if no response come till 1000 ms
whether socket get timeout and get disconnected or it do not disconnect socket and give empty string in readme.
Actually neither. A SocketTimeoutException is thrown.
From the docs:
setSoTimeout
public void setSoTimeout(int timeout)
throws SocketException
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. The option must be enabled prior to entering the blocking
operation to have effect. The timeout must be > 0. A timeout of zero
is interpreted as an infinite timeout.
Parameters: timeout - the specified timeout, in milliseconds.
Throws: SocketException - if there is an error in the underlying protocol, such as a TCP error.
The socket will not disconnect. Instead, any reading method will throw a SocketTimeoutException that you may wish to catch in your program. The socket can still be used, but readme in such a case will not be defined:
String readme;
try
{
readme = bs.readline;
// TODO do stuff with readme
}
catch (SocketTimeoutException e)
{
// did not receive the line. readme is undefined, but the socket can still be used
socket.close(); // disconnect, for example
}
It is assumed in the example that IOExceptions are caught elsewhere or thrown.
The docs explain this behaviour quite well: Socket.setSoTimeout(int)
I have long-lasting TCP connection between two computers (second not under my control). Second computer can send FIN flag at every moment, and first must close connection corrent (send FIN flag back to second computer).
How can I know that the second computer sending a FIN flag and when I must cause socket.close() method of my Java application?
Normally, you have to read the connection and when this returns -1 for EOF or an appropriate IOException, you can close the connection. Note: SocketTimeoutException doesn't mean the connection is closed.
an example.
boolean ok = false;
try {
int b = in.read();
ok = b >= 0;
if (!ok)
throw new EOFException();
} finally {
if (!ok)
in.close();
}
Detecting a soft connection close by the other side (when they manage to send FIN/RST flags) is only partially possible with the old Java I/O library. You will learn of a broken connection only via a timeout, so it may be far from immediate. Your threads may hang for a long time before they realize that the party at the other end is long gone.
In order to handle it better, you need to use nio. There, such a situation will be recognized by the Selector saying there is data ready for reading but then read on the channel returning less than zero. This will allow you to learn about soft connection resets almost immediately.
On the other hand, a hard connection termination (e.g. someone cutting the wire or network being down) can only be detected via timeouts regardless of which libraries you use as it's a property of the TCP protocol itself.
As explained above, the Socket's properties (isClosed, isConnected, etc) are not helpful. A proper solution would be to set a reasonable SO_TIMEOUT and read from the socket:
In case of connection closed by the peer, the read operation would return with '-1'
In case of read timeout, the read operation would throw SocketTimeoutException.
(Scala code)
val socket = new Socket("localhost", 8888)
socket.setSoTimeout(10000) /* Set reasonable read timeout */
try {
val res = socket.getInputStream().read()
if (res < 0)
... /* Socket closed */
else
... /* Socket read succeeded */
} catch {
case _: SocketTimeoutException => ... /* Socket not closed */
case _ => ... /* Merde */
}