Why is exception not thrown when the connection is terminated? [duplicate] - java

This question already has answers here:
How do you detect a network disconnection when downloading a file in java?
(2 answers)
Closed 7 years ago.
I am here to solve an issue i am facing. I hope to get some help from the experts.
Below is a code of a simple file downloader in java. I want to detect an exception when the connection is broken in the middle of downloading a file. Now, I run the code and in the middle of downloading the file, i turn off my wifi with keyboard wifi off button. Doing this the program hangs forever without throwing any exceptions and without terminating. It seems it blocks forever. Firstly my confusion is why is exception not thrown? Secondly, in the following code you can see this line //con.setReadTimeout(2000); which is currently commented out. Removing the comment and running the program, now if connection breaks in the middle by turning off wifi then it waits for 2 seconds and then if it cannot read then it terminates without throwing exception. So, again in this case why is it just terminating and not throwing any exception? I am very puzzled by this behavior. I hope i can get some help. Thank you very much!
import java.io.FileOutputStream;
import java.net.URL;
import java.net.URLConnection;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import java.util.*;
public class Main {
public static void main(String[] args) {
try{
URL website = new URL("http://128f1.downloadming1.com/bollywood%20mp3/Jai%20Ho%20(2014)/06%20-%20Naacho%20Re%20-%20DownloadMing.SE.mp3");
URLConnection con = website.openConnection();
//con.setReadTimeout(2000);
ReadableByteChannel rbc = Channels.newChannel(con.getInputStream());
FileOutputStream fos = new FileOutputStream("song.mp3");
fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
}
catch(Exception e){
System.out.println("got here");
e.printStackTrace();
}
System.out.println("Done downloading...");
}
}

TCP connections are designed to deal with unreliable networks and packet loss. If your network connection is gone, it will not know unless you set the SO_KEEPALIVE socket option (java.net.SocketOptions has some documentation of that option).
Unfortunately, URLConnection does not allow you to set this or any other socket option. And even if it did, the keep alive interval would be very high, two hours on most operating systems. The keep alive interval can only be changed in your operating system settings, it can not be changed through Java (the SocketOptions.SO_KEEPALIVE documentation is confusing in that regard).
Altogether, you don't get an exception because the underlying network protocol is not designed to detect whether your network medium was disrupted after the initial establishment of the connection.
As you found out, setReadTimeout helps somewhat, however you have bumped into an undocumented feature of the transferFrom method. The actual implementation of that method is in sun.nio.ch.FileChannelImpl.transferFromArbitraryChannel. I am pasting the JDK 7 code here:
private long transferFromArbitraryChannel(ReadableByteChannel src,
long position, long count)
throws IOException
{
// Untrusted target: Use a newly-erased buffer
int c = (int)Math.min(count, TRANSFER_SIZE);
ByteBuffer bb = Util.getTemporaryDirectBuffer(c);
long tw = 0; // Total bytes written
long pos = position;
try {
Util.erase(bb);
while (tw < count) {
bb.limit((int)Math.min((count - tw), (long)TRANSFER_SIZE));
// ## Bug: Will block reading src if this channel
// ## is asynchronously closed
int nr = src.read(bb);
if (nr <= 0)
break;
bb.flip();
int nw = write(bb, pos);
tw += nw;
if (nw != nr)
break;
pos += nw;
bb.clear();
}
return tw;
} catch (IOException x) {
if (tw > 0)
return tw;
throw x;
} finally {
Util.releaseTemporaryDirectBuffer(bb);
}
}
As you can see in the catch block, if some data was already written to the target, it will ignore any IOException and just return the number of bytes that were written.

Related

Java: Is PrintWriter providing some form of "clue" about the request-origin platform's preferred line endings?

This is about java.io.PrintWriter from Oracle JDK 8
I've written a small test to make sure some TCP-interfacing service (we don't own this service!) always returns CRLF and nothing else.
However, I notice that tests which are expected to fail (containing only LF) are passing...
When debugging the test, I see that the response is fine (only CRLF) - but we have a user that's complaining that he's still receiving the response with LF!
My thought currently is that: since I am using printWriter.println(query);, perhaps println() from the PrintWriter class (especially the ln part!) is providing my current CRLF (I am running the tests from a Win10 machine) and the server is trying to be nice and is therefore adapting the line endings according to clues received from the source.
I will commission a linux test box and I will write a simple application to confirm my conjecture above. However, even if I manage to find some correlation (I will update here), I would still like to confirm, with someone who knows the PrintWriter class, that this is indeed the location where things get "customized" and cause the server to switch line ending composition...
For example: Perhaps it's not PrintWriter, but the TcpIpService of the machine that is providing this clue? And therefore, my correlation here does not point to the cause of different responses (I.E.: It's not Java, it's the OS)
Update: Before trying it in linux, I tried changing the println into print but then the buffReader.read() (a java.io.BufferedReader method) gets "stuck".
I tried also swapping println() for write() and flush() - read() is stuck again.
How should I refactor the println() method I am using, to have control over the line endings provided? I would like to be able to simulate CRLF, CR and LF.
Update: I am including a small program to reproduce the part that I am interested in. Unfortunately, I am still quite far from obtaining a linux machine to see if the output from this program changes under linux:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
public class NewWhoisClient {
public static void main(String[] args) {
int portNumber = 43;
String whoisHostName = "213.248.242.76";
String query = "nic.beer";
Socket whoisSocket;
PrintWriter printWriter;
BufferedReader buffReader;
try {
whoisSocket = new Socket(whoisHostName, portNumber);
buffReader = new BufferedReader(
new InputStreamReader(whoisSocket.getInputStream())
);
printWriter =
new PrintWriter(whoisSocket.getOutputStream(),true);
} catch (IOException e) {
throw new AssertionError("Socket setup failed", e);
}
try {
printWriter.println(query);
StringBuilder responseWIP = new StringBuilder();
int value;
while ((value = buffReader.read()) != -1) {
responseWIP.append((char) value);
}
String result = responseWIP.toString();
///
if (result.contains("\r\n")) {
System.out.println("Result contained CRLF");
} else {
System.out.println("Some other line ending or no CRLF at all");
}
///
} catch (Exception e) {
throw new AssertionError("Socket communication failed", e);
}
}
}

java socket outputstream and broken pipe

I have to send a dynamic buffer size to the socket stream.
It works correctly, but when I try to send multiple buffers with a size
bigger than
int my_buffer_size =18 * 1024; (this is an indicative value)
I get the error (for some write):
Java.net.SocketException: Broken pipe
at java.net.SocketOutputStream.socketWrite0(Native Method)
My code is very simple:
For example If I want to send a big file I read a file stream with
byte[] bs = new byte[my_buffer_size];
while (... ){
fileInputStream.read(bs);
byte[] myBufferToSend = new byte[sizeBuffer];
DataOutputStream out = new DataOutputStream(cclient.getoutputStream());
out.writeInt(myBufferToSend.length);
out.write(myBufferToSend);
out.flush();
}
(The file is just a test the buffer size can be variable)
the SendBufferSize is 146988.
Is there a way to fix the broken pipe error? I read around but actually I didn’t solve the problem.
Thank you
any help is appreciated
I use the classic ServerSocket serverSocket;
and Socket cclient
'Broken pipe' means that you've written data to a connection that has already been closed by the other end.
Ergo the problem lies at the other end, not in this code. Possibly the other end doesn't really understand your length-word protocol for example, or doesn't implement it correctly.
If it's anything like this code it won't, because you're ignoring the result returned by read() and assuming that it fills the buffer. It isn't specified to do that, only to transfer at least one byte.
In common, receiving huge blocks is not supported by DataInputStream, because the readmethod just delegates to the underlying socket input stream and that socket input stream does not complain about not having read all. E.g. in Oracle Java 8 you get some 2^16 bytes and the rest is ignored. So when you close the socket after DataInputStream.read has returned, the sender node observes a "pipe broken" while still trying the send the rest of the huge block. Solution is a windowed read. Below is a DataInputStream-subclass, which does precisely this.
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
public class HugeDataInputStream extends DataInputStream
{
int maxBlockLength;
public HugeDataInputStream(InputStream in)
{
this(in, 0x8000);
}
public HugeDataInputStream(InputStream in, int maxBlockLength)
{
super(in);
this.maxBlockLength = maxBlockLength;
}
public int readHuge(byte[] block) throws IOException
{
int n = block.length;
if (n > maxBlockLength)
{
int cr = 0;
while (cr < n)
{
cr += super.read(block, cr, Math.min(n - cr, maxBlockLength));
}
return cr;
}
else
{
return super.read(block);
}
}
}

Running out of File Descriptors with Connector.open

Here is most of the relevant code, running on a cRIO with the FRC Java image:
try {
SocketConnection http = (SocketConnection) Connector.open("socket://" + BEAGELIP);
InputStream data = http.openInputStream();
database = "";
int p = data.read();
while (p >= 0) {
database += (char) p;
p = data.read();
}
data.close();
http.close();
} catch (Exception e) {
System.out.println(e);
}
This method is being repeatedly called.
After repeated failures to connect (e.g., the server is not plugged in), the IOException switches from java.io.IOException: ConnectException: connect refused to java.io.IOException: errno: 24 on fd:-1 during socket create
We think the reason this might be happening is because on failure, Connector.open returns null, which we cannot close(), freezing up a filedescriptor.
What is the correct way to prevent all of the file descriptors from being used up in this procedure?
If anyone can give a suggestion on how this should be done, that would be wonderful.
Your closes must be in a finally {} block. Otherwise they don't happen if there was an exception, and there will be an exception sooner or later,

Socket not Receiving Input in Java 7

I have run into an interesting issue trying to upgrade one of my applications from the Java 6 to Java 7. It is a simple Java socket program. It sends a command to a COM socket and receives a response. It works perfectly in a Java 6 environment, but when I try to run the same code in a Java 7 environment, the socket appears to receive nothing in the InputStream.
I can confirm that the COM socket it's connecting to does receive the command and sends the response. This is run on the exact same machine in both cases with the firewall disabled, and it's the exact same code ran both times.
Has something changed in Java 7, do I have some deeper flaw, or is this simply a Java bug?
Here is a slightly stripped version of the code.
public static void main(String[] arguments) throws Exception {
InetAddress server = InetAddress.getByName(serverAddress);
Socket sock = SSLSocketFactory.getDefault().createSocket(server.getHostAddress(), port);
InputStream in = sock.getInputStream();
OutputStream out = sock.getOutputStream();
out.write(command.getBytes()); //Is valid command
String token = "";
responseReader: while (true) {
try {
Thread.sleep(1);
}
catch (InterruptedException exception) {}
byte[] d = new byte[in.available()];
int avail = in.read(d);
for (int i = 0; i < avail; i++) {
if (d[i] == fieldSeperator) {
token = "";
}
else if (d[i] == commandSeperator) {
break responseReader;
}
else {
token += (char) d[i];
}
}
}
}
I've tried as much as I can think of, most of the time knowing it shouldn't matter. Using different methods of reading the stream, casting to SSLSocket and making different calls, adding some sleeps.
The code is wrong. You shouldn't use available() like that. If there is no data available you will allocate a zero length buffer and execute a zero length read, which will retun zero without blocking. Use a constant like 8192 for the buffer size, and allocate the buffer outside the loop. And get rid of the sleep() too.
There are few if any correct uses of available(), and this isn't one of them.
And note that available() always returns zero for an SSLSocket, and has always done so right back to Java 1.3 and the separate JSSE download. So I am unable to accept that the same code worked in Java 6.

How to close a thread in Java?

I'm very new to Java, and I'm trying to modify an example of a socket server to power a flash-based game. To allow flash to connect to the server, I need to serve up a policy file.
I've never coded a server application before, so I'm not too familiar with the things which need to happen.
Anyway, I have made it so that it outputs the file, but for some reason it does so 10 times.
I need to close the thread before it continues to do it again. Below is the code I have, with a comment where I need to close the thread.
import java.io.*;
import java.net.*;
import java.util.Random;
public class Main {
private static int port=4041, maxConnections=0;
// Listen for incoming connections and handle them
public static void main(String[] args) {
int i=0;
try{
ServerSocket listener = new ServerSocket(port);
Socket server;
while((i++ < maxConnections) || (maxConnections == 0)){
doComms connection;
server = listener.accept();
doComms conn_c= new doComms(server);
Thread t = new Thread(conn_c);
t.start();
}
} catch (IOException ioe) {
System.out.println("IOException on socket listen: " + ioe);
ioe.printStackTrace();
}
}
}
class doComms implements Runnable {
private Socket server;
private String line,input;
doComms(Socket server) {
this.server=server;
}
public void run () {
char EOF = (char)0x00;
input="";
try {
// Get input from the client
DataInputStream in = new DataInputStream (server.getInputStream());
PrintStream out = new PrintStream(server.getOutputStream());
while((line = in.readLine()) != null && !line.equals(".")) {
input=input + line;
if(line.trim().equals("h")){
out.println("h"+EOF);
}
else if(line.trim().equals("i")){
Random randomGenerator = new Random();
int randomInt = randomGenerator.nextInt(4);
out.println("b"+randomInt+EOF);
}
else if(line.trim().equals("c")){ System.out.println("Player collision.");}
else if (line.trim().equals("<policy-file-request/>")) {
out.println("<?xml version=\"1.0\"?>\n<!DOCTYPE cross-domain-policy SYSTEM \"http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd\"><cross-domain-policy>\n<site-control permitted-cross-domain-policies=\"all\"/>\n<allow-access-from domain=\"*\"/>\n</cross-domain-policy>"+EOF);
System.out.println("Responded to policy request");
// I need to close the thread / disconnect the client here.
}
else System.out.println("Unknown command: "+line.trim());
}
server.close();
} catch (IOException ioe) {
System.out.println("IOException on socket listen: " + ioe);
ioe.printStackTrace();
}
}
}
Also, a small extra thing, in NetBeans, it underlines "import java.io.*;" and says incorrect package, but it still works fine.
Edit:
I've worked out that the reason it sends it 10 times is that it is receiving 10 lines in a single send operation. I have tried adding a "return;" under where it sends the policy XML, but it still doesn't seem to d/c the client. I should also note than I am intending for this to be a multiplayer server, so I need to keep the socket open and just close one thread.
At first glance, your run() method looks like it should terminate normally. I suspect your loop:
while((i++ < maxConnections) || (maxConnections == 0)){
Since maxConnections is initialized to 0 and is never incremented, the loop seems to run infinitely and create many threads - probably as many as the socket can accept listeners. And then it breaks out from the loop with an IOException. Is this what's actually happening?
Update: apparently not... out of ideas for now.
Your code makes sense. What is your input? If you have 10 lines saying "<policy-file-request/>" , then indeed it will print the file 10 times. What about all the other if clauses you have there? In each one you print something + EOF, but surely you just want to print one response per request. Also your 'input' variable is unused.
The thread will die after you return from doComms.run(). Please capitalize the start of class names in Java: it should be DoComms, just to make the code easier to follow for other Java programmers.
To close the connection, your call to server.close() should do it. To make sure the output is sent fully first, you should call close() or flush() on your PrintStream before you call Socket.close().
What input are you sending? It looks like if you only send <policy-file-request/> once from the client, you'll only get the file once.
Not sure about NetBeans, but is it complaining that you don't have a package specified at the top of your .java file? Try adding the following package declaration, with the path relative to the top of the NetBeans project:
package my.path.to.this.directory;
I'd suggest running both the server and the client in a debugger and stepping through the execution to see what happens at each point in time. This will help you confirm the expected values at every point. Eclipse and other Java IDEs have pretty good (and easy-to-use) debuggers.
As far as your code:
I would do line.trim() once for each
loop iteration, instead of
trim()'ing repeatedly and
unnecessarily creating extra
objects.
Make sure the client and server both flush() the Socket's OutputStream after each request/response. If the socket's OutputStream has not been flushed, the InputStream on the other end of the connection may block waiting for input, while the OutputStream blocks waiting to fill its buffer.
What does the code in the client
look like? Are you sure it's
sending a null or "." to close the
connection? Do you need to trim() before checking for a "."
As others have mentioned, your code does not follow typical Java coding conventions. I'd suggest getting up to speed by reading the published code conventions for Java.

Categories

Resources