Файл, переданный клиенту, является беспорядком - PullRequest
0 голосов
/ 10 ноября 2019

Каждый раз, когда сервер передает файл, в заголовке указывается дескриптор файла и конечный индекс. Если файл разделен двоеточиями, вывод сервера в порядке, но когда дело доходит до клиента, он становится беспорядком。

Длина кода такая длинная, но простая.

сервер:

package niotest;

import java.io.File;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.nio.charset.Charset;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.Iterator;

public class NIOServerTest {
    public static void main(String[] args)throws IOException {
        new Server(new InetSocketAddress(1235)).start();
    }
}
class Server{
    private static final int BUFF_SIZE_RE=1024;
    private static final int BUFF_SIZE_SE=1024*1024;
    private ServerSocketChannel serverSocketChannel;
    private Selector selector;
    private InetSocketAddress port;
    private boolean ing;
    private String rootPath;
    Server(InetSocketAddress port){
        this.port=port;
    }
    void start()throws IOException {
        this.serverSocketChannel=ServerSocketChannel.open();
        this.serverSocketChannel.configureBlocking(false);
        this.serverSocketChannel.socket().bind(this.port);
        this.ing=true;
        this.selector=Selector.open();
        this.serverSocketChannel.register(this.selector, SelectionKey.OP_ACCEPT);
        new Thread(new Listener()).start();
        this.rootPath="F:\\xiazai\\";
        System.out.println("server starting……");
    }
    private void stop(){
        this.ing=false;
    }
    class Listener implements Runnable{
        @Override
        public void run(){
            while(Server.this.ing){
                try {
                    selector.select();
                    Iterator<SelectionKey> keys= selector.selectedKeys().iterator();
                    while(keys.hasNext()){
                        SelectionKey key=keys.next();
                        keys.remove();
                        if(key.isValid()){
                            if(key.isAcceptable()){
                                doCon(key);
                            }else if(key.isReadable()){
                                handleRead(key);
                            }
                        }
                    }

                }catch (IOException ioe){
                    ioe.printStackTrace();
                }
            }
            try{
                selector.close();
                serverSocketChannel.close();
            }catch (IOException IOE){
                IOE.printStackTrace();
            }

        }
        void doCon(SelectionKey key)throws IOException{
            SocketChannel sc=((ServerSocketChannel)(key.channel())).accept();   //
            sc.configureBlocking(false);
            sc.register(selector,SelectionKey.OP_READ);
        }
        void handleRead(SelectionKey key) {
            SocketChannel sc = (SocketChannel) key.channel();
            ByteBuffer buffer = ByteBuffer.allocate(BUFF_SIZE_RE);
            try {
                int len = sc.read(buffer);

                if (len > 0) {
                    buffer.flip();
                    byte[] bytes = new byte[buffer.remaining()];
                    buffer.get(bytes);
                    String meg = new String(bytes);

                    System.out.println("Request FileName: "+meg);
                    buffer.clear();

                    if (meg.equals("end;")) {
                        key.cancel();
                        key.channel().close();
                        stop();
                    }else {
                        new Thread(new FileHandler(Server.this.rootPath + meg, sc)).start();
                    }
                } else if (len < 0) {
                    key.cancel();
                    sc.close();
                }
            }catch (IOException IOE){
                IOE.printStackTrace();
                key.cancel();
            }
        }
        class FileHandler implements Runnable{
            private String fileName;
            private SocketChannel out;
            FileHandler(String fileName,SocketChannel out){
              this.fileName=fileName;
              this.out=out;
            }
            @Override
            public void run(){
                try {
                    handleTransfer();
                }catch (IOException | InterruptedException ioe){
                    try {
                        out.close();
                    }catch (IOException ie){
                        ie.printStackTrace();
                    }
                    ioe.printStackTrace();
                }
            }
            private void handleTransfer()throws IOException,InterruptedException{
                ByteBuffer littleBuffer=ByteBuffer.allocate(BUFF_SIZE_RE);
                File file=new File(this.fileName);
                if(file.exists()&&file.isFile()) try
//                        (
//                        FileChannel in = FileChannel.open(Paths.get(this.fileName), StandardOpenOption.READ)
//                )
                {
                    FileChannel in = FileChannel.open(Paths.get(this.fileName), StandardOpenOption.READ);
                    long len = in.size();
                    if (in.size() < 1024 * 1024 * 50) {
                        this.fileName = this.fileName.replace("../", "");
                        String[] temp = this.fileName.split("\\\\");
                        int fd = (int) (Math.random() * 100);
                        String saveName = fd + temp[temp.length - 1];

                        System.out.println("The size of file " + saveName + " is " + len + " , fd is " + fd);

                        littleBuffer.put(("Y;" + fd + ";" + len + ";" + saveName + ";").getBytes());
                        littleBuffer.flip();
                        this.out.write(littleBuffer);
                        littleBuffer.clear();

                        Thread.sleep(3000);

                        littleBuffer.clear();
                        transfer(in, littleBuffer, fd);
                        in.close();
                    }else {
                        System.out.println("The file " + fileName + " too big!");
                        littleBuffer.put(("N;" + fileName+";too big!").getBytes());
                        littleBuffer.flip();
                        this.out.write(littleBuffer);
                    }
                    }catch(IOException ioe){
                    ioe.printStackTrace();
                }

                else {
                    System.out.println("The file " + fileName + " is doesn't exist or is a Directory!");
                    littleBuffer.put(("N;" + fileName+";is doesn't exist or is a Directory!").getBytes());
                    littleBuffer.flip();
                    this.out.write(littleBuffer);
                }
            }
            private void transfer(FileChannel in,ByteBuffer littleBuffer,int fd) throws IOException{
                final int HEAD_SIZE=(BUFF_SIZE_RE+"").length();
                ByteBuffer buffer=ByteBuffer.allocate(BUFF_SIZE_SE);
                byte[] temp=new byte[BUFF_SIZE_RE];
                while ((in.read(buffer)) != -1){
                    buffer.flip();

                    while(buffer.position()<buffer.limit()){
                        int len=buffer.limit()-buffer.position();
                        int tempRead;

                        String dataHead;

                        if(len>(BUFF_SIZE_RE-HEAD_SIZE-3)) {
                            dataHead=fd+":"+BUFF_SIZE_RE+":";
                            tempRead =BUFF_SIZE_RE-dataHead.length();
                          }
                        else {
                            int fdLen=fd>9?2:1;
                            int lenLen=(len+":").length();
                            int allLen=fdLen+1+lenLen+len;
                            dataHead=fd+":"+allLen+":";
                            tempRead =len;
                        }

                        littleBuffer.put(dataHead.getBytes(Charset.forName("UTF-8")));


                        System.out.println(littleBuffer.position());
                        System.out.println(tempRead);
                        buffer.get(temp,0,tempRead);

                        littleBuffer.put(temp,0,tempRead);

                        for(int i=0;i<(BUFF_SIZE_RE-tempRead-dataHead.length());i++){
                            littleBuffer.put("\0".getBytes());
                        }

                        System.out.println(littleBuffer.limit());
                        System.out.println(new String(littleBuffer.array()));

                        littleBuffer.flip();

                        this.out.write(buffer);

                        littleBuffer.clear();
                    }
                    buffer.clear();
                }
            }
        }
    }
}

Клиент:

package niotest;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

public class NIOClientTest {
    public static void main(String[] args) throws IOException{
        new Client(new InetSocketAddress("localhost",1235)).start();
    }
}
class Client {
    private static final int BUFF_SIZE=1024;
    private SocketChannel sc;
    private Selector selector;
    private boolean ing;
    private final ByteBuffer bb;
    private Map<Integer,FileObject > downMap;
    private String downPath;

    Client(InetSocketAddress isa) throws IOException {
        this.sc = SocketChannel.open();
        this.sc.configureBlocking(false);
        this.sc.connect(isa);
        this.selector = Selector.open();
        this.sc.register(this.selector, SelectionKey.OP_CONNECT);
        this.ing = true;
        bb=ByteBuffer.allocate(BUFF_SIZE);
        this.downPath="F:\\multiThreadDL";
        this.downMap=new HashMap<>();
    }

    void start() {
        System.out.println("client start");
        File path=new File(this.downPath);
        if(!path.exists()) path.mkdir();
        new Thread(new KeyboardInput()).start();
        new Thread(new Listener()).start();
    }

    private void stop() {
        this.ing = false;
    }

    class KeyboardInput implements Runnable {
        @Override
        public void run() {
            BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
            while (Client.this.ing) {
                if (sc.isConnected()) {
                    try {
                        String input = br.readLine();
//                        System.out.println(input);
                        synchronized (bb) {
                            bb.clear();
                            if (input.equals("exit;")) {
                                bb.put("end;".getBytes());
                                bb.flip();
                                sc.write(bb);
                                br.close();
                                stop();
                                break;
                            }
                            bb.put(input.getBytes());               //本来写成了get,导致白白移动了position,却没有内容,内容是空的,服务器就输出不了。
                            bb.flip();
                            sc.write(bb);
                        }
                        } catch(IOException ioe){
                            ioe.printStackTrace();
                        }

                    }
            }

        }
    }

    class Listener implements Runnable {
        @Override
        public void run() {
            while (Client.this.ing) {
                try {
                    selector.select();
                    Iterator<SelectionKey>keys=selector.selectedKeys().iterator();
                    while(keys.hasNext()) {
                        SelectionKey key = keys.next();
                        keys.remove();
                        if (key.isValid()) {
                            if(key.isConnectable()&&!sc.isConnected()){
                                sc.finishConnect();
                                sc.register(selector, SelectionKey.OP_READ);
                            }
                            if(key.isReadable()) {
                                handleRead(key);
                            }
                        }
                    }
                } catch (IOException ioe) {
                    ioe.printStackTrace();
                    stop();
                }

            }
            try{
                selector.close();
                sc.close();
            }catch (IOException ioe){
                ioe.printStackTrace();
            }

        }
        private void handleRead(SelectionKey key)throws IOException {
            SocketChannel sc = (SocketChannel) key.channel();
            synchronized (bb) {                         //虽然通道是双向的,但这样公用一个缓冲区,就要做同步,很耗性能。
            bb.clear();

                int len = sc.read(bb);
                System.out.println(len);
                if (len > 0) {
                    byte[] bytes = new byte[len];
                    bb.flip();                             //绝杀之句。不加这一句,又会读不出东西来。
                    bb.get(bytes);



                    String[] temp;
                    String meg=meg = new String(bytes, 0, len);
                    if(meg.startsWith("N")||meg.startsWith("Y")) {
                        temp = meg.split(";");

                        if (meg.startsWith("N") && temp.length==3) {
                            System.out.println("The file  " + temp[1] + " : "+temp[2]);
                        } else if (meg.startsWith("Y") && temp.length==4) {
                            FileChannel out=FileChannel.open(Paths.get(Client.this.downPath+"\\"+temp[3]), StandardOpenOption.READ,StandardOpenOption.CREATE,StandardOpenOption.WRITE);
                            int fd=Integer.parseInt(temp[1]);
                            long size=Integer.parseInt(temp[2]);
                            Client.this.downMap.put(fd,new FileObject(size,temp[3],out));

                        }
                    }else{
                        meg=new String(bytes,0,(BUFF_SIZE+"").length()+4,"UTF-8");
                        System.out.println(meg);
                        temp=meg.split(":",2);
                        int fd=Integer.parseInt(temp[0]);
                        int endIndex=Integer.parseInt(temp[1]);

                        bb.clear();

                        int offset=temp[0].length()+1;
                        bb.put(bytes,offset,endIndex-offset);    //不知道为什么要这样写?看一下三参put的源码就知道了,
                                                                        // 第三个参数指的是长度,而不是指结束位置,所以叫偏移而不是截取

                        bb.flip();
                        if(Client.this.downMap.containsKey(fd)) {
                            FileObject fb = Client.this.downMap.get(fd);

                            int written=bb.remaining();
                            fb.setDowned(written);

                            if((written+fb.fileBuffer.position())>=fb.fileBuffer.capacity()){
                                fb.fileBuffer.flip();
                                fb.getOut().write(fb.fileBuffer);
                                fb.fileBuffer.clear();

                            }

                            fb.fileBuffer.put(bb);

                            if(fb.isCompeleted()){
                                fb.fileBuffer.flip();
                                fb.getOut().write(fb.fileBuffer);
                                System.out.println(fb.getFileName() + ": 100%");
                                Client.this.downMap.remove(fd);
                                fb.getOut().close();
                            }else {
                                String outPut=fb.getFileName() + ": " + fb.getPercent()+"%";
                                System.out.println(outPut);

//                                StringBuilder backOut=new StringBuilder();
//                                for(int i=0;i<outPut.length();i++){
//                                    backOut.append("\b");                   //java中\b没有用
//                                }
//                                System.out.println(backOut.toString());
                            }


                        }else {
                            System.out.println("野包? "+fd);
                        }
                    }

                } else if (len < 0) {
                    key.cancel();
                    sc.close();
                }
            }
        }
    }
    class FileObject{
        private static final int FILE_BUFF_SIZE=5*1024*1024;
      private FileChannel out;
      private long fileSize;
      private long downed;
      private String fileName;
      ByteBuffer fileBuffer;
      FileObject(long fileSize,String fileName,FileChannel out){
          this.fileSize=fileSize;
          this.out=out;
          this.downed=0;
          this.fileName=fileName;
          this.fileBuffer=ByteBuffer.allocate(FILE_BUFF_SIZE);
      }
      void setDowned(int hasGet){
          this.downed+=hasGet;
      }
      boolean isCompeleted(){
          return this.downed==this.fileSize;
      }
      int getPercent(){
          return (int)(((double)this.downed/(double)this.fileSize)*100.0d);
      }
      String getFileName(){
          return this.fileName;
      }
      FileChannel getOut(){
          return  this.out;
      }


    }
}

запуск сервера …… Имя файла запроса: bizhi1.jpeg Размер файла 28bizhi1.jpeg - 278605, fd - 28 8 1016 102428: 1024: ���� JFIF ��; СОЗДАТЕЛЬ: gd-jpeg v1.0 (с использованием IJG JPEG v62), качество = 90 �� C

�� 8� »��
�A �}! 1AQa "q2�� # B��R�� $ 3br�% & '() 456789: CDEFGHIJSTUVWXYZcdefghijstuvwxyz�������������������������
�� � w! 1AQaq "2B���� # 3R�br� �� ^, ��_C] �r�� @ ��h�B�P�ҷ, / RO�W [� = yU��th�c����PΤ���� ��I� = j���, �Ӛ��c�q���, # �ҵ / 0m-� [RL� ^ ~ Z�4�6N��H�-������aZ�S� ��e��� �s��� $ 3��Eu7z���dY g + ����eWE�f�b; �s�wj����� ��Ug�h��N + �RL����]г [KWzWQ1͸r
ск | ֩) п $ уу] KL B��� \ 7м [9YS����6�Ud�F��X% �isD��) � ֶ, ��� ',

запуск клиента bizhi1.jpeg 26 1024 V��� # �� Исключение в потоке«Thread-1» java.lang.NumberFormatException: для входной строки: «V��� # ��» в java.lang.NumberFormatException.forInputString (NumberFormatException.java:65) в java.lang.Integer.parseInt (целое число. java: 580) в java.lang.Integer.parseInt (Integer.java:615) в niotest.Client $ Listener.handleRead (NIOClientTest.java:156) в niotest.Client $ Listener.run (NIOClientTest.java:106) вjava.lang.Thread.run (Thread.java:748)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...