Socket Exception

I have code for transferring files (thanks for help so far). The trouble is, after the file has been received, the client sends "exit" to the server, which is supposed to read that, and close the socket. However, for some reason, the server is blocking and not receiving the command, until the socket is closed, giving me an exception. I know I could bypass this by simply putting a Try Catch in there, but that's just avoiding the error rather than figuring out why it is happening? I have (in the client):

public WebClient()throws IOException{

String fileName ="test.txt";//this is the hard-coded file that will be requested.

Socket socket =null;

PrintWriter out =null;

BufferedReader in =null;

boolean outputToTerminal =true;//so that bytes from a file transfer aren't displayed to the terminal window.

File file =new File(fileName);//a little too much hard-coding, but it's only an example.

try{

socket =new Socket("127.0.0.1", 8008);

out =new PrintWriter(socket.getOutputStream(),true);

in =new BufferedReader(new InputStreamReader(socket.getInputStream()));

}

catch (UnknownHostException e){

System.out.println("Couldn't resolve address: 127.0.0.1");

System.exit(1);

}

catch (IOException e){

System.out.println("Couldn't get I/O for the connection to: 127.0.0.1");

System.exit(1);

}

BufferedReader stdIn =new BufferedReader(new InputStreamReader(System.in));

System.out.println(in.readLine());//This is the greeting message from the server.

String sent ="GET " + fileName;//hardcoded.

out.println(sent);

System.out.println(">" + sent);//The > is for display purposes, to show "user" commands.

while (outputToTerminal){

String received = in.readLine();

if (received.startsWith("File size:")){//This comes just before the bytes are sent.

outputToTerminal =false;//no more commands are to be displayed until the transfer is complete.

}

System.out.println(received);

}

file.createNewFile();//this file will be filled with the sent bytes.

FileOutputStream testFile =new FileOutputStream(file.toString());

//in.close();

DataInputStream dataInput =new DataInputStream(socket.getInputStream());

byte received[] =newbyte[socket.getReceiveBufferSize()];

int test = dataInput.read(received);

System.out.println(test);

while (test != -1){

testFile.write(received);

test = dataInput.read(received);

}

testFile.close();//the file channel is closed.

//dataInput.close();

//in = new BufferedReader(new InputStreamReader(socket.getInputStream()));

System.out.println(received);

System.out.println(in.readLine());//the last two strings sent by the server, again, hardcoded.

sent ="EXIT";

System.out.println(">" + sent);

out.println(sent);//tells the server we are finished.

//out.close(); //cleaning up.

//in.close();

//stdIn.close();

//socket.close();

}

Where all the close()s were commented out to see if they were causing the problem.

In the server:

publicclass WebServer

{

private File file;

private Socket client =null;

private PrintWriter terminal;

publicstaticvoid main(String[] args)throws IOException{

WebServer webServer =new WebServer();

}

public WebServer()throws IOException{//static void main(String[] args) throws IOException {

ServerSocket server =null;

try{

server =new ServerSocket(8008);

}catch (IOException e){

System.out.println("Unable to listen to Port 8008.");

System.exit(1);

}

try{

client = server.accept();

}catch (IOException e){

System.err.println("Connection failed.");

System.exit(1);

}

terminal =new PrintWriter(client.getOutputStream(),true);

BufferedReader command =new BufferedReader(new InputStreamReader(client.getInputStream()));

terminal.println("Welcome to Jimmy's webserver.");

String input;

try{

while ((input = command.readLine()) !=null){

if (input.toLowerCase().equals("exit")){

break;

}

elseif (input.toLowerCase().equals("help")){

terminal.println("Commands:");

terminal.println("GET <filename> - JWS will send <filename> to you.");

terminal.println("EXIT - exits Jimmy's Webserver.");

}

elseif (input.toLowerCase().startsWith("get ")){

sendFile(new File(input.substring(4)));

}

}

terminal.close();

command.close();

client.close();

server.close();

}

privatevoid sendFile(File file)throws FileNotFoundException, IOException{

if (file ==null){

terminal.println("Please use the command: GET filename");

}

elseif (!file.exists()){

terminal.println(file.toString() +" could not be found in the current directory.");

}

else{

terminal.println("Sending file: " + file.toString());

terminal.println("File size: " + file.length() +"bytes.");

Long time = System.currentTimeMillis();

FileInputStream fileReader =new FileInputStream(file);

byte buffer[] =newbyte[client.getReceiveBufferSize()];

//terminal.close();

DataOutputStream dataTerminal =new DataOutputStream(client.getOutputStream());

//terminal.close();

while (fileReader.read(buffer) != -1){

dataTerminal.write(buffer);

}

fileReader.close();

//dataTerminal.close();

terminal =new PrintWriter(client.getOutputStream());

dataTerminal.close();

terminal.println("Transfer of " + file.toString() +" is complete.");

time = System.currentTimeMillis() - time;

if (time == 0){ time++;}

terminal.print("Transfer took: " + time +" milliseconds. ");

terminal.close();

}

}

}

I do appreciate there is a lot of code there, but I thought rather than extracting some and have you wondering some aspects, I might as well paste the whole thing.

The line that is blocking (and eventually crashing) is:

while ((input = command.readLine()) !=null){

Any help you can give me would be greatly appreciated. Thank-you.

[11721 byte] By [abu5ea] at [2007-11-26 19:23:10]
# 1

Too many streams. Redo it all with just one input and output stream or reader per socket.

You can only really run one kind of input stream or reader per socket, and one kind of output stream or writer. Otherwise they will all interfere with each other, read each other's data, ... Look at all those buffers.

Also don't use PrintWriter or PrintStream with sockets unless you like not knowing what went wrong, as they swallow exceptions.

Your file writing loops are wrong. Should be like this:

int count;

while ((count = in.read(buffer)) > 0)

out.write(buffer, 0, count);

otherwise you will write junk at the end of the file.

ejpa at 2007-7-9 21:44:26 > top of Java-index,Java Essentials,Java Programming...
# 2

Thanks a lot for replying.

Which streams would you use? I want to be able to send and receive a byte array (so DataInputStream, DataOutputStream), but also send string prompts to the user - which I don't think is possible with Data I/O streams (short of sending a char array and putting it back together at the other end).

Any suggestions?

abu5ea at 2007-7-9 21:44:26 > top of Java-index,Java Essentials,Java Programming...
# 3
Actually, using DataOutputStream and string.toCharArray() should work, if I use DataInputStream and string = new String(charArray) I shoud be able to make this work pretty easily.Thank-you.
abu5ea at 2007-7-9 21:44:26 > top of Java-index,Java Essentials,Java Programming...
# 4
See DataInputStream.readUTF() and DataOutputStream.writeUTF()
ejpa at 2007-7-9 21:44:26 > top of Java-index,Java Essentials,Java Programming...
# 5

Ok thank-you, I've implemented that. Sorry to bother you again, but I'm back to my original problem (the reason I endedup using more than one stream in the first place) - when I try and send a ByteArray over the DataStream, if the DataStream is used again, the -1 EOF marker is never sent, causing my code to just block. I could (possibly?) send "-1" through the DataStream and see if that worked, but I can see that causing even more problems.

Also, this line doesn't seem to make a difference:

out.write(buffer, 0, count);

, this is (I think) because the byte array being sent through is of a constant size, and this is the int that is returned by in.read(buffer), despite how many zeros are in there, so it is still writing the full buffer to the file, unless I am misunderstanding?

Thanks again

--Edit - nevermind the first question, that was a stupid mistake on my part. I had while (input != -1) { send input }, and then I was expecting the -1 at the other end. School boy error. Thanks anyway.

Message was edited by:

abu5e

abu5ea at 2007-7-9 21:44:26 > top of Java-index,Java Essentials,Java Programming...
# 6

write(buffer,0,count) is always required. There is no guarantee anywhere that read always fills the buffer. In any case, unless the file size is an exact multiple of the buffer length, which you can't rely on, the last read must return a count < buffer.length.

So you have to write only as much as you read. Any more is junk.

ejpa at 2007-7-9 21:44:26 > top of Java-index,Java Essentials,Java Programming...
# 7

Sorry to bother you again, but I am still having major problems with this code blocking.

The server method is:

terminal = new DataOutputStream(client.getOutputStream());

FileInputStream fileReader = new FileInputStream(file);

byte buffer[] = new byte[client.getReceiveBufferSize()];

int n = 0;

while (n != -1) {

n = fileReader.read(buffer);

terminal.write(buffer);

}

and the client method (that is blocking) is:

in = new DataInputStream(socket.getInputStream());

FileOutputStream fileWriter = new FileOutputStream(file.toString());

byte received[] = new byte[socket.getReceiveBufferSize()];

int rec = 0;

while (in.read(received) != -1) {

rec = in.read(received); //this is the line that is blocking

fileWriter.write(received);

//I AM planning to sort the above line out, once I have everything else working.

}

I can't understand why this code is blocking, when debugging I noticed it receives TWO buffers of size >8000b for a file of size 12bytes, so it must be receiving the next message from the server (that is all I can think), but the server code definately gets a -1 from the file input, and because I reshuffled the code, that buffer should be sent across the DataOutputStream, but it is never being received.

Any ideas?

abu5ea at 2007-7-9 21:44:26 > top of Java-index,Java Essentials,Java Programming...
# 8

I think this has something to do with the DataOutputStream not actually having anything to do with the FileInput, and so the -1 from the file input doesn't affect the value of the DataOutputStream.

The trouble is, I can't think of a way around this, short of telling the client to expect a byte array followed by a boolean sent through the DataOutputStream telling it whether another byte array is to come, repeatedly, which is very inefficient. How would you guys go about solving this?

Thanks a lot.

abu5ea at 2007-7-9 21:44:26 > top of Java-index,Java Essentials,Java Programming...
# 9

You are still having major problems with this code because you still haven't taken the advice I gave you.

Instead, you've coded two copying loops in two different ways, neither of which is what I suggested, and both of which contain major errors.

If you don't want to take advice, fine, but then why ask?

ejpa at 2007-7-9 21:44:27 > top of Java-index,Java Essentials,Java Programming...
# 10

Erm, I did put a comment in to explain that I will handle writing to the file better once I had the socket sending the end of file properly, because I want to change as little as possible while doing the debugging so as not to introduce any further problems, then once the code is saving the file (albeit with useless data at the end), I can work on making the file saving better.

That is the only reason I haven't taken your advice about the fileWriter.write method - not wanting to add more confusion for myself.

I am a little confused as to what you mean about two copying loops, unless you mean the one for reading the file - in which case I don't understand the problem? I have rewrote the code so it only uses two streams for the socket - DataInputStream and DataOutputStream, so I have taken your advice as much as I could, and I am, of course, willing to enhance the code with any suggestions you are willing to make, I just wanted to debug the socket part first.

Please don't think that by not implementing your filewriting code, that this means I don't appreciate your help, because I do, I just don't think that part is the reason is the code is currently erroring.

Any suggestions as to how I can transmit this EOF character, or at least let the loop know it has finished, will be greatly appreciated.

Thank-you.

abu5ea at 2007-7-9 21:44:27 > top of Java-index,Java Essentials,Java Programming...
# 11

I have found that if I do this once the file has been sent:

while ((fileReader.read(buffer) != -1)) {

terminal.write(buffer);

}

terminal.close();

terminal = new DataOutputStream(client.getOutputStream());

The client no longer blocks in the receiving loop, it does, however, now throw a null pointer exception if I try to use the same input stream (I think the null pointer is for the received data rather than the stream), or a SocketException because the socket is closed if I try reinitializing the input stream.

The two variations I have tried are:

while (rec != -1) {

rec = in.read(received);

fileWriter.write(received);//, 0, count);

}

fileWriter.close(); //the file channel is closed.

System.out.println(received);

System.out.println(in.readUTF()); //the last two strings sent by the server, again, hardcoded.

Which throws the null pointer, and

while (rec != -1) {

rec = in.read(received);

fileWriter.write(received);//, 0, count);

}

fileWriter.close(); //the file channel is closed.

System.out.println(received);

in = new DataInputStream(socket.getInputStream());

System.out.println(in.readUTF()); //the last two strings sent by the server, again, hardcoded.

which throws the SocketException. In both cases is it the last line that throws the exception.

Any ideas how I can resolve this? Thank-you for looking.

abu5ea at 2007-7-9 21:44:27 > top of Java-index,Java Essentials,Java Programming...
# 12
Try to insert fileWriter.flush() immediately after fileWriter.write() in your server.
alex_yershova at 2007-7-9 21:44:27 > top of Java-index,Java Essentials,Java Programming...
# 13

Sorry, I should have been more specific.

It's in.read() that is blocking, not fileWriter, because it is continually waiting a byte array from the socket, that will never come, because the socket isn't sending any more byte arrays (everything else sent will be by writeUTF().

Thank-you for looking

abu5ea at 2007-7-9 21:44:27 > top of Java-index,Java Essentials,Java Programming...
# 14
You are right, I looked in the wrong place, but still - insert flush() whenever you call write():while (fileReader.read(buffer) != -1) {dataTerminal.write(buffer);dataTerminal.flush();}Message was edited by: alex_yershov
alex_yershova at 2007-7-9 21:44:27 > top of Java-index,Java Essentials,Java Programming...
# 15
Thanks for everyone's help. This post has been double-posted(ish), and most of the code above has been completely re-written.Thank-you anyway, but please don't waste your time trying to debug it any further.
abu5ea at 2007-7-21 17:34:28 > top of Java-index,Java Essentials,Java Programming...