网络编程之——文件上传案例分析

TCP文件上传案例

原理:

客户端读取本地的文件,把文件上传到服务器,服务器把传输过来的文件保存到服务器的本地硬盘上

  1. 中间涉及本地流(和本地硬盘)和网络流(客户端和服务端)
  2. 文件上传的原理就是文件的复制
  3. 下载和上传过程类似

代码

整个代码的核心就是文件流的输入与输出
TCPClient

package FileUpload;

import java.io.*;
import java.net.Socket;
/*
 实现步骤:
        1.创建一个本地字节输入流FileInputStream对象,构造方法中绑定要读取的数据源
        2.创建一个客户端Socket对象,构造方法中绑定服务器的IP地址和端口号
        3.使用Socket中的方法getOutputStream,获取网络字节输出流OutputStream对象
        //核心
        4.使用本地字节输入流FileInputStream对象中的方法read,读取本地文件
        5.使用网络字节输出流OutputStream对象中的方法write,把读取到的文件上传到服务器

        6.使用Socket中的方法getInputStream,获取网络字节输入流InputStream对象
        7.使用网络字节输入流InputStream对象中的方法read读取服务回写的数据
        8.释放资源(FileInputStream,Socket)
 */
public class TCPClient {
    public static void main(String[] args) throws IOException {
        //        1.创建一个本地字节输入流FileInputStream对象,构造方法中绑定要读取的数据源
        // 不管什么格式都读成字节流(所以可以兼容所有的格式的上传下载)
        FileInputStream fileInputStream = new FileInputStream("D:\\Project\\chromedriver_win32.zip");
        //        2.创建一个客户端Socket对象,构造方法中绑定服务器的IP地址和端口号
        Socket socket = new Socket("127.0.0.1",8088);
        //        3.使用Socket中的方法getOutputStream,获取网络字节输出流OutputStream对象
        OutputStream os = socket.getOutputStream();
        int len = 0;
        byte[] bytes = new byte[1024];//这是利用数组的缓存读取,可以提高效率
        //这个len和byte会被一直的赋值
        //        4.使用本地字节输入流FileInputStream对象中的方法read,读取本地文件
        while ((len=fileInputStream.read(bytes))!=-1){
            //        5.使用网络字节输出流OutputStream对象中的方法write,把读取到的文件上传到服务器
            System.out.println(len);
            os.write(bytes,0, len);
        }
        /*  注意:这句必须加,不然read没有数据的时候会堵塞,不会返回len的值
            解决:上传完文件,给服务器写一个结束标记
            void shutdownOutput() 禁用此套接字的输出流。
            对于 TCP 套接字,任何以前写入的数据都将被发送,并且后跟 TCP 的正常连接终止序列。
         */
        socket.shutdownOutput();
        //        6.使用Socket中的方法getInputStream,获取网络字节输入流InputStream对象
        InputStream is = socket.getInputStream();

        while((len=is.read(bytes))!=-1){
            //        7.使用网络字节输入流InputStream对象中的方法read读取服务回写的数据
            System.out.println(new String(bytes, 0, len));
        }
        //        8.释放资源(FileInputStream,Socket)
        fileInputStream.close();
        socket.close();
    }
}

注意:fis.read()方法读取的是本地文件,结束标记是读取到-1结束,但是while循环是不会把-1写进去的,这样相当于服务器在执行is.read()的时候,是找不到文件的结束标记的(写过来的就没有结束标记),这样read方法将被阻塞,所以不会返回len的值,会一直等待结束标记,所以在客户端进行写的时候,手动添加结束标志
TCPServer

package FileUpload;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

//保存到本地,并给客户端回传“上传成功”
public class TCPServer {
    public static void main(String[] args) throws IOException {
        //1.创建一个服务器的ServerSocket对象,和系统指定的端口
        ServerSocket server = new ServerSocket(8088);
        //2.获取客户端的Socket对象
        Socket socket = server.accept();
        //3.使用客户端Socket中的文件输入流对象
        InputStream is = socket.getInputStream();
        File file = new File("D:\\Project\\copy");
        //4.判断文件夹是否存在
        if(!file.exists()){
            file.mkdirs();
        }
        //5.创建一个本地字节流输出对象,构造方法中传递进去要生成的文件名
        FileOutputStream fos = new FileOutputStream(file+"\\1.zip");
//        FileInputStream fis = new FileInputStream(file);
        int len = 0;
        byte[] bytes = new byte[1024];
        //6.提高效率,通过从socket的输出流中拿出数据,写入本地的输入流中
        while ((len=is.read(bytes))!=-1){
            System.out.println(len);
            fos.write(bytes,0,len);
        }
        System.out.println("while没有死循环");
        //.网络二进制流输出对象
        OutputStream os = socket.getOutputStream();
        //7.
        os.write("上传成功".getBytes());
        fos.close();
        socket.close();
        server.close();

    }

}

优化

可以将服务器一直启动,并使用多线程进行提高效率
注意在多线程重写run的时候,是没法抛出异常的,所以只能通过try,catch运行
TCPServer

package ThreadFileUpload;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.sql.Time;
import java.util.Date;
import java.util.Random;
import java.util.Timer;

//保存到本地,并给客户端回传“上传成功”
public class TCPServer {
    public static void main(String[] args) throws IOException {
        //1.创建一个服务器的ServerSocket对象,和系统指定的端口
        ServerSocket server = new ServerSocket(8088);
        /*
            使用多线程技术,提高程序的效率
            有一个客户端的请求上传文件,就开启一个线程,完成文件的上传
         */
        while(true){
            new Thread(new Runnable() {
                //重写的函数没有抛出异常(这样异常就抛出不出),所以只能放在try,catch中
                @Override
                public void run() {
                    try{
                        //2.获取客户端的Socket对象
                        Socket socket = server.accept();
                        //3.使用客户端Socket中的文件输入流对象
                        InputStream is = socket.getInputStream();
                        File file = new File("D:\\Project\\copy");
                        //4.判断文件夹是否存在
                        if(!file.exists()){
                            file.mkdirs();
                        }
                        //随机文件名防止重复
                        String fileName = System.currentTimeMillis()+new Random().nextInt(999999)+".zip";
                        System.out.println(fileName);
                        //5.创建一个本地字节流输出对象,构造方法中传递进去要生成的文件名
                        FileOutputStream fos = new FileOutputStream(file+"\\"+fileName);
//        FileInputStream fis = new FileInputStream(file);
                        int len = 0;
                        byte[] bytes = new byte[1024];
                        //6.提高效率,通过从socket的输出流中拿出数据,写入本地的输入流中
                        while ((len=is.read(bytes))!=-1){
                            fos.write(bytes,0,len);
                        }
//                        System.out.println("while没有死循环");
                        //.网络二进制流输出对象
                        OutputStream os = socket.getOutputStream();
                        //7.
                        os.write("上传成功".getBytes());
                        fos.close();
                        socket.close();
//                        server.close();
                    }catch (IOException e){
                        System.out.println(e);
                    }
                }
            }).start();//开启这个线程,来一个开启一个
        }

    }
}

BS服务器分析

其实就是通过前端的接口(Socket)访问服务器(Server),根据请求信息(html的路径信息等,通过socket的outputsstream发送过来),然后返回一个html文件和它的图片数据等(通过通过IO流,以及html页面里的一些图片数据),这样就实现了网页请求(就和请求读取图片是一样的,网页的素材文件都是存在服务器上的),如果网页里有图片,那么就要一直启动着,他会先请求页面,然后再请求图片的数据

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
题目如下: 编写程序实现文件上传功能。 有能力的同学可以自行设计文件下载功能,但是本次作业不要求。 服务器端: 要求能运行如下程序: java FileServer port foldername 实际的运行命令可能为 java FileServer 1234 d:\\share 解释如下: port为服务器开放的网络连接端口 foldername为服务器上某个文件夹,该文件夹存放客户端上传的文件。 客户端: 要求能运行如下程序: java FileClient server_ip port afile java FileClient server_ip port afolder 实际的运行命令可能为 java FileClient 127.0.0.1 1234 d:\\abc\\a.docx java FileClient 127.0.0.1 1234 d:\\abc 上面的程序运行完毕后,在服务器的文件下将看到客户端上传的文件a.docx 能看到客户端上传的文件夹abc,并且abc文件夹下的所有文件和子文件夹都上传到了服务器。 假设客户端有文件夹d:\\abc,该文件夹有子文件若干,有子文件夹若干。 客户端能够将某个文件上传到服务器,也可以将某个文件夹连同文件夹下的所有子文件和子文件夹 全部上传到服务器,服务器端保存客户端的文件夹结构和文件信息。 文件传输过程要求实现内容加密,加密算法任意,可以是DES,AES,RSA之类的算法都可以。 注意:是文件在传输过程中加密,到服务器保存的时候,要求和客户端的文件内容一样, 服务器端的文件并不需要加密。 要求支持多客户端并发上传文件,不考虑文件名冲突,假设多个客户端同时上传的文件没有重名现象。 必须使用多线程编程。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值