0

I have problem with filetransfer using SocketChannels: client ends to transfer the file, but the server still wait more byte from client. This causes a timeout, and the file will be saved less than a small part. The server remains stucked here: "fileChannel.transferFrom(socketChannel, 0, fileLength);". Everything that happens before is working properly.

server:

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.RandomAccessFile;
import java.nio.channels.FileChannel;
import java.nio.channels.SocketChannel;

import javax.imageio.ImageIO;

public class RequestHandler implements Runnable {

private SocketChannel socketChannel;

BufferedReader stringIn;

public RequestHandler(SocketChannel socketChannel) {
    this.socketChannel = socketChannel;
    // this.serverSocketChannel = socketChannel;
    System.out.println("RequestHandler initialized");
}

public static int getLastPush(String dir) {
    return new File("./" + dir).listFiles().length + 1;
}

public void run() {

    LoadConfig config = null;
    try {
        config = new LoadConfig();
    } catch (IOException e) {
        e.printStackTrace();
    }

    String type = null;

    try {

        socketChannel.socket().setSoTimeout(10000);
        MainServer.log("Client connected from: " + socketChannel);

        // Prendere immagine
        DataInputStream dis = new DataInputStream(socketChannel.socket().getInputStream());

        // Leggo string
        stringIn = new BufferedReader(new InputStreamReader(socketChannel.socket().getInputStream()));

        // Invio al client
        DataOutputStream dos = new DataOutputStream(socketChannel.socket().getOutputStream());

        // leggo in ricezione
        MainServer.log("Attendo auth");
        String auth = stringIn.readLine();

        // check auth
        MainServer.log("Auth ricevuto: " + auth);

        String pass = config.getPass();
        if (pass.equals(auth)) {
            dos.writeBytes("OK\n");
            System.out.println("Client Authenticated");

            type = stringIn.readLine();
            System.out.println("fileType: " + type);

            dos.writeBytes(type + "\n");

            Integer i = getLastPush(config.getFolder());

            String fileName = i.toString();
            System.out.println("fileName: " + fileName);

            switch (type) {

            case "img":

                // transfer image
                int len = dis.readInt();
                System.out.println("Transfer started.");
                byte[] data = new byte[len];
                dis.readFully(data);
                System.out.println("Transfer ended.");

                File toWrite = new File(config.getFolder() + "/" + fileName + ".png");

                ImageIO.write(ImageIO.read(new ByteArrayInputStream(data)), "png", toWrite);

                dos.writeBytes("http://" + config.getDomain() + "/" + toWrite.getName());

                break;
            case "file":

                // transfer file
                System.out.println("Transfer started.");

                readFileFromSocket(config.getFolder() + "/" + fileName + ".zip");
                System.out.println("Transfer ended.");

                System.out.println("Sending link...");
                dos.writeBytes("http://" + config.getDomain() + "/" + fileName + ".zip");

                break;
            default:

            }

            i++;

            System.out.println("Chiudo");
            dos.close();
            dis.close();
            stringIn.close();
        } else {
            dos.writeBytes("Invalid Id or Password");
            System.out.println("Invalid Id or Password");
            dos.close();
            dis.close();
            stringIn.close();
        }

        socketChannel.close();

    } catch (Exception exc) {
        exc.printStackTrace();
    }
    System.out.println("----------");
}

public void readFileFromSocket(String fileName) {
    RandomAccessFile aFile = null;
    try {
        aFile = new RandomAccessFile(fileName, "rw");
        FileChannel fileChannel = aFile.getChannel();

        long fileLength = Long.parseLong(stringIn.readLine());
        System.out.println("File length: " + fileLength);

        fileChannel.transferFrom(socketChannel, 0, fileLength);
        fileChannel.close();

        Thread.sleep(1000);
        fileChannel.close();
        System.out.println("End of file reached, closing channel");

    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }

}

}

client:

import java.awt.AWTException;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.RandomAccessFile;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.net.UnknownHostException;
import java.nio.channels.FileChannel;
import java.nio.channels.SocketChannel;

import javax.imageio.ImageIO;

public class Uploader {
    private BufferedImage img;
    private byte[] bytes;
    private SocketChannel socketChannel;
    private String link;
    private String fileName;

    DataOutputStream dos;

    // Per gli screen parziali
    public Uploader(Rectangle r, String ip, int port) throws IOException, AWTException {

        SocketChannel socketChannel = createChannel(ip, port);
        this.socketChannel = socketChannel;

        Rectangle screenRect = new Rectangle(0, 0, 0, 0);
        for (GraphicsDevice gd : GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices()) {
            screenRect = screenRect.union(gd.getDefaultConfiguration().getBounds());
        }

        this.img = new Robot().createScreenCapture(screenRect).getSubimage(r.x, r.y, r.width, r.height);

        ByteArrayOutputStream outputArray = new ByteArrayOutputStream();
        ImageIO.write(img, "png", outputArray);
        outputArray.flush();
        this.bytes = outputArray.toByteArray();
        outputArray.close();
    }

    // Per gli screen completi
    public Uploader(BufferedImage bi, String ip, int port) throws IOException {

        SocketChannel socketChannel = createChannel(ip, port);
        this.socketChannel = socketChannel;
        this.img = bi;

        ByteArrayOutputStream outputArray = new ByteArrayOutputStream();
        ImageIO.write(img, "png", outputArray);
        outputArray.flush();
        this.bytes = outputArray.toByteArray();
        outputArray.close();
    }

    // Per i file
    public Uploader(String fileName, String ip, int port) throws UnknownHostException, IOException {

        SocketChannel socketChannel = createChannel(ip, port);
        this.socketChannel = socketChannel;

        // this.socket = new Socket(ip, port);
        this.fileName = fileName;
    }

    public void send(String pass, String type) throws IOException {

        dos = new DataOutputStream(socketChannel.socket().getOutputStream());
        BufferedReader stringIn = new BufferedReader(new InputStreamReader(socketChannel.socket().getInputStream()));

        try {
            socketChannel.socket().setSoTimeout(10000);

            // send auth
            System.out.println("Sending auth");
            dos.writeBytes(pass + "\n");
            System.out.println("Auth sent: " + pass);
            this.link = stringIn.readLine();
            // this.link = os.println();
            System.out.println("Auth reply: " + link);
            if (this.link.equals("OK")) {

                System.out.println("Sending type: " + type);
                dos.writeBytes(type + "\n");

                // Controllo e aspetto che il server abbia ricevuto il type
                // corretto
                if (stringIn.readLine().equals(type)) {

                    System.out.println("Il server riceve un: " + type);

                    switch (type) {

                    // image transfer
                    case "img":

                        System.out.println("Uploading image...");

                        dos.writeInt(bytes.length);
                        dos.write(bytes, 0, bytes.length);
                        dos.flush();

                        break;

                    // file transfer
                    case "file":

                        sendFile(fileName);

                        break;

                    // default case, hmm
                    default:

                        break;
                    }

                    // return link
                    System.out.println("Waiting link...");
                    this.link = stringIn.readLine();
                    System.out.println("Returned link: " + link);

                    bytes = null;
                } else {
                    System.out.println("The server had a bad interpretation of the fileType");
                }

            } else {
                System.out.println("Closed");
            }

            dos.close();
            stringIn.close();
            socketChannel.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public SocketChannel createChannel(String ip, int port) {

        SocketChannel socketChannel = null;
        try {
            socketChannel = SocketChannel.open();
            SocketAddress socketAddress = new InetSocketAddress(ip, port);
            socketChannel.connect(socketAddress);
            System.out.println("Connected, now sending the file...");

        } catch (IOException e) {
            e.printStackTrace();
        }
        return socketChannel;
    }

    public void sendFile(String fileName) {
        RandomAccessFile aFile = null;
        try {
            File file = new File(fileName);
            aFile = new RandomAccessFile(file, "r");
            FileChannel inChannel = aFile.getChannel();

            long bytesSent = 0, fileLength = file.length();
            System.out.println("File length: " + fileLength);
            dos.writeBytes(fileLength + "\n");

            // send the file
            while (bytesSent < fileLength) {
                bytesSent += inChannel.transferTo(bytesSent, fileLength - bytesSent, socketChannel);
            }
            inChannel.close();

            Thread.sleep(1000);
            System.out.println("End of file reached..");
            aFile.close();
            System.out.println("File closed.");

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }

    public String getLink() {
        return link;
    }

}
SergiX44
  • 371
  • 2
  • 5
  • 15

1 Answers1

1

You're losing data in the BufferedReader. If you look at the file that has been received you'll see that part of it is missing at the beginning.

You can't mix buffered and unbuffered input on the same channel. I suggest you use a DataInputStream and use read/writeUTF() to transfer the filename, andread/writeLong() to transfer the length.

I can't imagine why you're using different code to transfer images and other files. It's all bytes.

user207421
  • 305,947
  • 44
  • 307
  • 483