OIO下的socket传输文件

OIO下的io操作

正常的情况下,我们的服务端连接是同步进行的,所以每次收到客户端的连接后都需要等待当前客户端处理完毕之后才会继续处理下一个请求。这个OIO下的网络编程的缺点,但是我们可以使用单独的线程来进行对客户端的请求进行处理,这样也能提高服务器端的并发性。当然,这样其实也是很麻烦的,因为每次有请求进来,我们都要创建一个新的线程,所以这样也会消耗许多的系统进程,比如一些线程直接的上下文切换等等。
当然也有解决的方法,那就是使用多路复用,其实对应在Java中就是nio模式,这里就不详细提及了。
客户端代码

package day01;

import configure.IOUtil;
import configure.NioDemoConfig;

import java.io.*;
import java.net.Socket;
import java.util.logging.Logger;

/**
* @Auther: yu
* @Date: 2020/7/9 23:55
* @Description: oio下的网络编程
*/
public class BlockSendClient extends Socket {
   private Socket client;
   private FileInputStream fileInputStream;
   private DataOutputStream dataOutputStream;


   /**
    * 构造函数,创建socket对象
    * @throws IOException
    */
   public BlockSendClient() throws IOException {
       super(NioDemoConfig.SOCKET_SERVER_IP,NioDemoConfig.SOCKET_SERVER_PORT);
       this.client = this;
       Logger.getGlobal().info("Client[port:"+client.getLocalPort()+"] 成功连接服务器");
   }
   /**
    * 像服务器传输文件
    */
   public void sendFile(){
       try {
           File file = new File(NioDemoConfig.SOCKET_SEND_FILE);
           if (file.exists()){
               fileInputStream = new FileInputStream(file);
               dataOutputStream = new DataOutputStream(client.getOutputStream());
               //文件名和长度
               dataOutputStream.writeUTF("copy_"+file.getName());
               dataOutputStream.flush();
               dataOutputStream.writeLong(file.length());
               dataOutputStream.flush();

               //开始传输文件
               Logger.getGlobal().info("=========开始传输文件=========");

               int length = 0;
               int progress = 0;
               byte[] bytes = new byte[1024];

               while ((length=fileInputStream.read(bytes,0,bytes.length))!=-1){
                   dataOutputStream.write(bytes,0,length);
                   dataOutputStream.flush();
                   progress += length;
                   Logger.getGlobal().info("|"+(100*progress/file.length())+"%|");
               }
               Logger.getGlobal().info("=========传输文件完毕=========");
           }
       } catch (Exception e) {
           e.printStackTrace();
       }finally {
           IOUtil.closeQuietly(dataOutputStream);
           IOUtil.closeQuietly(fileInputStream);
           IOUtil.closeQuietly(client);
       }
   }

   public static void main(String[] args)  {
       try
       {
           BlockSendClient client = new BlockSendClient(); // 启动客户端连接
           client.sendFile(); // 传输文件
       } catch (Exception e)
       {
           e.printStackTrace();
       }
   }
}


服务器端的代码:

package day01;

import configure.FormatUtil;
import configure.IOUtil;
import configure.NioDemoConfig;

import java.io.DataInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.text.DecimalFormat;
import java.util.logging.Logger;

/**
 * @Auther: yu
 * @Date: 2020/7/12 18:14
 * @Description:
 */
public class BlockReceiveServer extends ServerSocket {
    //服务器端口
    private static final int SERVER_PORT = NioDemoConfig.SOCKET_SERVER_PORT;
    //接受文件的路径 就是/
    private static final String RECEIVE_PATH = NioDemoConfig.SOCKET_RECEIVE_PATH;

    //保留1位有效数字
    private static DecimalFormat df = FormatUtil.decimalFormat(1);


    public BlockReceiveServer() throws IOException {
        super(SERVER_PORT);
    }

    /**
     * 启动服务器
     * 每一个客户端的文件使用一个线程处理
     */
    public void startServer() throws IOException {
        while (true){
            //server尝试接受其他的client的连接请求,server的accept方法是阻塞的
            Logger.getGlobal().info("server listen at:"+SERVER_PORT);
            Socket socket = this.accept();
            /**
             * 正常的情况下,我们党的服务端连接是同步进行的,所以每次收到客户端的连接后
             * 都需要等待当前客户端处理完毕之后才会继续处理下一个请求
             * 但是我们可以使用单独的线程来进行对客户端处理
             */

             new Thread(new Task(socket));


        }
    }

    /**
     * 用来处理传输文件的类对象
     */
    class Task implements Runnable{

        /**
         * 这个和前面的客户端的就是相反的,当然socket是我们操作的io的客户端
         * 客户端使用dos输出,所以我们使用dis接受
         * 客户端使用fis输入,所以我们使用fos进行输出保存文件
         */
        private Socket socket;
        private DataInputStream dis;
        private FileOutputStream fos;

        public Task(Socket socket) {
            this.socket = socket;
        }

        @Override
        public void run() {
            try {
                dis = new DataInputStream(socket.getInputStream());
                /**
                 * 客户端发送了writeUtf,所以我们对应使用readUTF以及readLong来读取数据
                 */
                String fileName = dis.readUTF();
                Long fileLength = dis.readLong();

                File directory = new File(RECEIVE_PATH);
                if (!directory.exists()){
                    directory.mkdir();
                }
                File file = new File(directory.getAbsolutePath() + File.separator + fileName);

                fos = new FileOutputStream(file);

                Long start = System.currentTimeMillis();
                Logger.getGlobal().info("文件接受开始");

                byte[] bytes = new byte[1024];
                int length = 0;
                int progress = 0;
                while ((length=dis.read(bytes,0,bytes.length))!=-1){
                    fos.write(bytes,0,length);
                    fos.flush();
                }
                Logger.getGlobal().info("文件接收完成");
                Logger.getGlobal().info("size:"+fileLength);
                Long end = System.currentTimeMillis();
                Logger.getGlobal().info("花费时间"+(end-start)+"ms");

            } catch (IOException e) {
                e.printStackTrace();
            }finally {
                IOUtil.closeQuietly(fos);
                IOUtil.closeQuietly(dis);
                IOUtil.closeQuietly(socket);
            }
        }
    }

    public static void main(String[] args) throws IOException {
        BlockReceiveServer server = new BlockReceiveServer();
        server.startServer();
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值