实现自动识别传输文件类型

服务端

public class ServerDemo {
public static void main(String[] args) throws IOException {
//1.创建服务器对象,指定端口
ServerSocket serverSocket = new ServerSocket(8899);
while (true) { //实现服务端持续服务
//2.等待接收客户端的链接accept
System.out.println(“等待客户端的链接。。。”);
Socket socket = serverSocket.accept();
System.out.println(“客户端连接成功!!”);

  1. //3.获取网络的输入流,获取客户端发送的字节信息<br /> InputStream netIn = socket.getInputStream();
  2. //先要读取文件名,然后再读取文件数据<br /> InputStreamReader isr = new InputStreamReader(netIn);//将字节输入流,转换成字符流<br /> BufferedReader br = new BufferedReader(isr);//把字符流转成缓冲流<br /> String fileName = br.readLine();//客户端传过来啥文件就是啥文件<br /> System.out.println("正在上传文件:" + fileName);
  3. //4.创建一个本地输出流,用来保存文件<br /> FileOutputStream localOut = new FileOutputStream("day12_demo/server/" + fileName);<br /> //将客户端的文件数据保存到本地<br /> int len;<br /> byte[] buf = new byte[8 * 1024];<br /> while ((len = netIn.read(buf)) != -1) {//从网络中读取客户端数据<br /> //读取的网络数据保存到文件<br /> localOut.write(buf, 0, len);<br /> }<br /> //5.获取一个网络输出流,告知客户端上传成功<br /> OutputStream netOut = socket.getOutputStream();<br /> netOut.write("恭喜上传成功!".getBytes());<br /> //6.释放资源<br /> localOut.close();<br /> socket.close();<br /> }<br /> }<br />}

客户端

public class ClientDemo {
public static void main(String[] args) throws IOException {
Scanner sc = new Scanner(System.in);
System.out.println(“请输入你要上传文件的路径”);
String filePath = sc.nextLine();
File uploadFile = new File(filePath);
if (!uploadFile.isFile()){
System.out.println(“你输入的文件不合法,请重新输入”);
return;
}
//1.创建Sacket对象,指定服务器的地址和端口
Socket socket = new Socket(“127.0.0.1”, 8899);
//2.获取一个输出流来发送文件数据
OutputStream netOut = socket.getOutputStream();

  1. //文件名按行发送就行了<br />String fileName = uploadFile.getName() + System.lineSeparator();//名字后缀都包括<br /> //String fileName = uploadFile.getName() + "/r/n";//名字和后缀都包括<br /> netOut.write(fileName.getBytes());//将带有换行的文件名传出
  2. //3.创建一个本地文件输入流,用来读取本地文件<br /> FileInputStream localIn = new FileInputStream(uploadFile);<br /> //4.边读边写<br /> int len;<br /> byte[] buf = new byte[8 * 1024];<br /> while ((len = localIn.read(buf)) != -1) {//读取本地文件<br /> //发送给服务器<br /> netOut.write(buf , 0 ,len);<br /> }<br /> //5.告诉服务器端,数据写出完毕<br /> socket.shutdownOutput();<br /> //6.获取一个网络的输入流,用来读取服务端相应的数据<br /> InputStream netIn = socket.getInputStream();<br /> len = netIn.read(buf);<br /> System.out.println("收到服务器的信息" + new String(buf , 0 , len));<br /> //7.释放资源<br /> localIn.close();<br /> socket.close();<br /> }<br />}

黑马云盘综合案例

学习目标

  • 理解需求,通过文档能够独立完成代码的开发

一 需求说明

image.png

实现一个乞丐版云盘。

云盘项目包含客户端和服务端,通过客户端可以查看网盘内容,可以下载网盘中的文件,上传文件到网盘中

二 概要设计

2.1 服务端实现


image.png

2.2 客户端实现

image.png

三 详细设计

3.1 技术选型

  1. 使用TCP编程技术实现客户端和服务端的开发,完成文件上下传的功能
  2. 自定义客户端和服务端之间的通讯协议
  3. 服务端多线程技术,实现高并发访问
  4. 自定义异常维护业务安全
  5. 使用JDK现有的API完成相关业务

    1. Socket,ServerSocket网络编程
    2. File文件类
    3. IO流相关类
    4. ResourceBundle配置文件读取

    image.png

3.2 协议定义

协议介绍

协议就是客户端和服务端通讯双方共同遵守的规定。

TCP协议是区分客户端服务端的一个比较底层的协议,传输的数据是字节码数据,如下
image.png

当客户端连接服务端后,若要上传一个文件到服务端。直接将文件数据传给服务端,那么服务端该如何识别这个数据呢。对于服务端来讲收到的都是字节数据,服务端该如何识别客户端的操作意图,如果是上传文件,那么文件的类型是什么,文件的名字是什么等等信息。

怎样让双方在沟通时理解对方的信息呢?

我们可以把要发送给对方的,我们可以称为头信息。这个头信息包含了我要干什么,我的数据有哪些属性等信息,发头信息后再把具体的数据发送给对方。这样对方先把头信息获取,知道了我要做什么操作,发送过来的数据是是什么有什么数据,再接收具体的数据,就搞定了。
image.png

加了头信息的数据如下:


image.png

自定义协议

我们约定双方发送数据前要先发送一个头信息,如下

  1. type=操作类型,fileName=文件名,status=操作状态,message=说明信息\r\n

说明:第一行头信息要和数据分开,用行分隔符分开即可,每个信息使用 key=value键值对表示,么个信息使用逗号分隔

  1. type:操作类型,对应的值可以是如下:
    ``` scan:表示浏览目录操作 upload:表示上传操作 download:表示下载操作

下载操作示例: type=download

  1. 2. fileName:要浏览操作文件的文件名

下载文件“美女.jpg”示例: type=download,fileName=美女.jpg

  1. 3. status:操作状态

表示服务端收到客户端请求后回复操作状态,ok表示成功,failed表示失败

  1. 4. message:说明信息

其他附加说明信息

  1. <a name="1ddf722b"></a>
  2. ##### 下载文件示例:
  3. **客户端发送请求:**

type=download,fileName=root/美女.jpg,status=null,message=null,\r\n

  1. **服务端响应请求:**
  2. - 成功

type=download,fileName=root/美女.jpg,status=ok,message=null,\r\n 01010101010010美女数据010100101001010

  1. - 失败
  2. ```java
  3. type=download,fileName=root/美女.jpg,status=failed,message=文件不存在!,\r\n

非常重要:文件要体现在服务端的位置。客户端看到的文件都是基于服务端某一个文件夹而存在的,我们把这个文件夹叫做root。
服务端开发时,需要指定一个合法的文件夹当做这个root。提供给客户端使用

协议的封装

为了方便协议的定义和解析,我们可以使用面向对象的思想进行封装成一个类,Protocol

  1. public class Protocol {
  2. //协议数据
  3. private String type;//操作类型
  4. private String fileName;//操作文件
  5. private String status;//操作状态
  6. private String message;//说明信息
  7. /**
  8. * 操作类型
  9. */
  10. public static class Type {
  11. public static final String SCAN="scan";//浏览
  12. public static final String UPLOAD="upload";//浏览
  13. public static final String DOWNLOAD="download";//浏览
  14. }
  15. /**
  16. * 操作状态
  17. */
  18. public static class Status {
  19. public static final String OK="ok";//成功
  20. public static final String FAILED="failed";//失败
  21. }
  22. //省略其他构造器及getter/setter
  23. //工具,快速获取协议的工具
  24. }

3.3 功能接口的定义

这里的接口,指定的是服务端暴露出来的功能。比如文件浏览功能,只要按照该接口指定的方式传输数据,就能完成功能了。

文件浏览

  • 客户端与服务端的交互流程
    image.png
  • 数据交互
    请求:客户端 —-> 服务端
    响应: 服务端 —->客户端

    1. type=scan,fileName=需要浏览的目录,status=null,message=null\r\n
    1. 成功:

      1. type=scan,fileName=需要浏览的目录,status=ok,message=null,
      2. xxx目录或者文件名称xxxxxx
      3. xxx目录或者文件名称xxxxxx
      4. xxx目录或者文件名称xxxxxx
    2. 失败:
      失败的原因,就是服务端没有对应的目录,无法遍历。

      1. type=scan,fileName=null,status=failed,message=目录不存在,只能浏览当前子目录,
      2. #没有后续数据

文件上传

  • 文件上传交换流程
    image.png
  • 数据交互
    请求:客户端 —-> 服务端
    1. type=upload,fileName=要上传的文件,status=null,message=null,

响应: 服务端 —->客户端

  1. 成功
    告诉客户端,文件可以上传的
    客户端收到信息后,继续上传文件信息,文件接收完毕后继续响应

    1. type=upload,fileName=要上传的文件,status=ok,message=null,
    1. type=upload,fileName=要上传的文件,status=ok,message=文件上传成功,
  2. 失败
    如果发现服务端已经存在该文件,提示客户端不要上传

    1. type=upload,fileName=要上传的文件,status=failed,message=文件已存在

文件下载

  • 文件下载流程
    image.png
  • 数据交互
    请求:客户端 —-> 服务端
    响应: 服务端 —->客户端

    1. type=download,fileName=下载的文件名,status=null,message=null,
    1. 成功
      需要将下载的文件字节数据保存到文件中

      1. type=download,fileName=下载的文件名,status=ok,message=134448,
      2. 010101010010下载的文件字节数据010101010010100101001010010010010101....
    2. 失败
      只有协议数据,没有实际下载的文件数据

      1. type=download,fileName=下载的文件名,status=failed,message=文件不存在,请选择当前存在的子文件,

3.4 基础架构

服务端架构

image.png

代码结构:

image.png
基础代码请看看今天资料

客户端架构

image.png

项目结构:

image.png

基础代码请看看今天资料

四 开发实战

基于资料中提供的基础框架代码,完成客户端和服务端的开发.

资料中有代码