简体   繁体   English

Java文件传输与SocketChannel

[英]java Filetransfer with SocketChannel

I have problem with filetransfer using SocketChannels: client ends to transfer the file, but the server still wait more byte from client. 我在使用SocketChannels进行文件传输时遇到问题:客户端结束了文件的传输,但是服务器仍然等待来自客户端的更多字节。 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);". 服务器仍然卡在这里:“ 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;
    }

}

You're losing data in the BufferedReader . 您正在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, and read/writeLong() to transfer the length. 我建议您使用DataInputStream并使用read/writeUTF()传输文件名,并使用read/writeLong()传输长度。

I can't imagine why you're using different code to transfer images and other files. 我无法想象为什么您使用不同的代码来传输图像和其他文件。 It's all bytes. 全部都是字节。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM