Search code examples
javasocketsserversocket

Socket transferring a file


I have a Java server class like this:

ServerSocket servsock = new ServerSocket(63456);
boolean read = false;
while (!read) {
    Socket sock = servsock.accept();
    int length = 1024;
    byte[] mybytearray = new byte[length];
    OutputStream os = sock.getOutputStream();
    BufferedInputStream bis = new BufferedInputStream(new FileInputStream(myFile));
    while (true) {
    int i = bis.read(mybytearray, 0, mybytearray.length);
    if (i == 1) {
        break;
    }
    os.write(mybytearray, 0, mybytearray.length);
    os.flush();
    }
    sock.close();
    read = true;
}

` And the client is like this:

Socket sock = new Socket("127.0.0.1", 63456);
byte[] mybytearray = new byte[1024];
InputStream is = sock.getInputStream();
FileOutputStream fos = new FileOutputStream("C:/tmp/NEWtmp.rar");
BufferedOutputStream bos = new BufferedOutputStream(fos);
int bytesRead = is.read(mybytearray, 0, mybytearray.length);
while(bytesRead != -1 ) {
    bos.write(mybytearray, 0, bytesRead);
    bytesRead = is.read(mybytearray, 0, mybytearray.length);
}
bos.close();
sock.close();

One question is: Why the loop does not stop at the end of the file? A second question would be, why is also so slow?


Solution

  • It does not stop because

    if (i == 1) {
    

    in your server source should be

    if (i == -1) {
    

    Or, if you want to be really safe:

    if (i <= 0) {
    

    Also, you risk data corruption with this line:

    os.write(mybytearray, 0, mybytearray.length);
    

    You should change this to:

    os.write(mybytearray, 0, i);
    

    On performance -- move the os.flush(); call to outside the while loop. When you flush a network stream, you are forcing it to dispatch any buffered data to the network. This is forcing the network layer to send and acknowledge 1024-byte TCP payloads (larger Ethernet payloads, of course) which is probably significantly smaller than your PMTU. You only need to flush when you are done sending data, or when you want the client to receive the buffered data now. Removing the flush call from each iteration will allow the OS-level network buffer to do its job, and segment the data into as few packets as possible.