0

I'm trying to write a java program to transfer files over a network from one device to another using Sockets. So I have two classes namely Server and Client to handle the program IO. I'm using FileInputStream to read the bytes of a local file into Client and Socket's OutputStream to send the read bytes to the Server. Here's

Code snippet of class Client :

int read;
System.out.print("Enter name of file to send : ");
String fileName = br.readLine();
File file = new File(fileName);
if(!file.exists()) {
    LISTENER.log(fileName + "does not exists."); // Exception Logging
    throw new IOException("File not found : " + fileName);
}
String parts[] = fileName.split("\\.");
String ext = parts[parts.length-1]; // Extracts the file extension
PrintWriter pw = new PrintWriter(sock.getOutputStream());
InputStream is = new FileInputStream(file);
pw.println(ext); // Sends file extension to the socket output stream
pw.flush();
while((read = is.read()) != -1) {
    os.write(read); // Sends read bytes to the socket output stream
    os.flush();
}

EXPLAINATION: So here I tried to get the file name and make a File object file. String ext extracts out the file extension and sends it to the Server through PrintWriter(so that at receiver end, it may create the file of the known extension). After that, InputStream is reads the file bytes and without buffering them into the class Client(for better performance), sends the read bytes directly through the socket OutputStream os.

Code snippet of class Server :

String ext; int read;
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
InputStream is = socket.getInputStream();
while(running) {
    ext = br.readLine(); // reads the file extension sent from client
    if(ext == null)
        throw new NullPointerException("File name provided does not have any specified extention");
    broadcast(ext); // sends the file extension back to all clients
    while((read = is.read()) != -1) {
        broadcast(read); // sends the read bytes to all clients
    }
}

EXPLAINATION: Here, Socket's InputStream Reader reads the first line which contains the file extension passed by Client through PrintWriter. broadcast(String) method is used to send the extension back to all Client implementations through PrintWriter. Then the bytes of File are read by the Socket's InputStream is read() method till it returns -1(end of stream). broadcast(int) sends the read bytes back to all Client implementations.

PROBLEM:

The class Server's InputStream is not reading all the bytes sent from class Clients's OutputStream and as a result it's stuck in the while((read = is.read()) != -1) loop because the stream never returned -1.

I tried to find the solution as to why the InputStream is not reading all bytes, but everywhere it was mentioned to use read(byte[],int,int) and not read(). But my question is why. Why InputStream is not reading all the bytes and why -1 is never returned in this case?

Pavel_K
  • 10,748
  • 13
  • 73
  • 186
Robin
  • 305
  • 2
  • 13
  • 3
    Do you understand that `read()` will only return -1 when the stream is closed, i.e. when the reader is certain that there will *never* be any more data? I don't see any sign of either the server or client closing their streams here... – Jon Skeet Aug 10 '17 at 17:00
  • As the above commenter mentioned, you need to close the socket outputStream if you want the -1 value. – drelliot Aug 10 '17 at 17:02
  • 1
    Another problem is that a BufferedReader... buffers the bytes it reads. So when you start reading bytes, you'll miss all the ones that have already been read and buffered by the BufferedReader. – JB Nizet Aug 10 '17 at 17:02
  • Also, reading and writing byte by byte is far from being more efficient than reading and writing chunks by chunks. You could just use Files.copy() to transfer the whole content of the file to the outpur stream. – JB Nizet Aug 10 '17 at 17:04
  • Are you saying it "is not reading all the bytes" because it never read the -1, or because it actually did not get all the file content? As @JonSkeet suggested, `read()` only returns -1 when the stream is closed, in this case the stream is closed only when the socket is closed. – jingx Aug 10 '17 at 17:05
  • @Jon Skeet I tried to close the `Client` InputStream and end up getting `java.net.SocketException: Connection reset` – Robin Aug 10 '17 at 17:07
  • 1
    Without more details of where you're getting that exception, it's not terribly helpful - you shouldn't get it when *reading*... are you sure you're not seeing that when *writing*? – Jon Skeet Aug 10 '17 at 17:10
  • BufferedReader reads a chunk of 8K from your InputStream to make its buffer. I assume, Your next read from InputStream tries to read (8K+1)th byte. – Minor Threat Aug 10 '17 at 17:11
  • @JonSkeet - When I closed the Client's writing streams(PrintWriter and OutputStream) I got `java.net.SocketException: Connection reset` and `java.net.SocketException: Broken pipe (Write failed)` respectively. You said to close the reading streams(InputStream on Server) but sorry I can't really figure out how to close it when it's stuck in the while loop – Robin Aug 10 '17 at 17:39
  • 1
    Well you need to ask yourself how either side should know when to close the connection. It's not really clear what you're trying to achieve here, but you need to explicitly think about what signals should be used by either the server or the client to close the connection. – Jon Skeet Aug 10 '17 at 17:42
  • @JonSkeet You said - "read() will only return -1 when the stream is closed." I made another rather simple version of this program, File sharing. Didn't close any Stream, didn't flush any stream and it's still working. Not only the InputStream.read() is returning -1 but it's also working properly without close() and flush() methods. – Robin Aug 11 '17 at 06:23
  • @Robin: I'm not going to speculate about code that I can't see. But if you're talking about a `FileInputStream` then sure, *that* will return -1 when it reaches the end of a file. But a socket-based stream won't return -1 until the socket is closed. – Jon Skeet Aug 11 '17 at 06:37
  • @JonSkeet Here's my Github Link to a basic version of [File-Sharing](https://github.com/chaitanyabhardwaj/file-sharing) using sockets. – Robin Aug 11 '17 at 15:40
  • I'm afraid I'm not going to start looking through a whole project (with no indication of where to look). The point of a [mcve] is that it's minimal. It would be entirely reasonable for you to include two minimal examples in the question: one which isn't working for you, and the other which works. – Jon Skeet Aug 11 '17 at 15:42

0 Answers0