网络编程——实验一:基于TCP&UDP的网络文件服务

目录

 

前言:本篇文章不提供知识点教学,只提供一些常见问题的解决方法和实现实验要求的学习路径

1 java IO

2 java Socket

2.1 创建简单的TCP连接

2.2 创建简单的UDP连接

2.3 创建多线程服务器+多用户连接服务器

3 文件传输

3.1 UDP文件传输

3.2 TCP文件传输

4 实现实验要求

3.1 简述实验要求

3.2 创建TCP和UDP的服务器端

3.2 使用TCP传输用户命令,使用UDP传输文件

3.3 文件目录管理


 

前言:本篇文章不提供知识点教学,只提供一些常见问题的解决方法和实现实验要求的学习路径

 

1 java IO

 

2 java Socket

 

2.1 创建简单的TCP连接

 

2.2 创建简单的UDP连接

 

2.3 创建多线程服务器+多用户连接服务器

 

3 文件传输

 

3.1 UDP文件传输

 

3.1.1 服务器端作为发送端,客户端作为接收端

 

3.1.1.1 问题分解

  1. 指定...

  2. 关于服务器端如何获取客户端的host和port:

    1. 已否决:通过客户端连接

      1.  // connect():连接UDP客户端和UDP服务器端
                 dgSocket = new DatagramSocket(); // 随机可用端口,又称匿名端口
                 dgSocket.connect(new InetSocketAddress(HOST, UDP_PORT));
          
    2. 尝试:UDP客户端发送一份数据给UDP服务器端,通过dp.getAddress()和dp.getPort()获取UDP客户端的端口号

 

3.1.1.2 关键问题

  1. 问题1:指定文件的大小(其实没必要,不用指定文件大小,每次按固定的大小循环传输直到传完所有的数据即可)

    1. 问题如下图所示:

    2. 网络编程——实验一:基于TCP&UDP的网络文件服务_第1张图片

    3. 服务器端代码:

       pw.println("文件大小:" + is.available() + " bytes"); // 告诉客户端要接收的文件的大小(单位:byte)
    4. 客户端代码:

       int length = Integer.parseInt(br.readLine()); // 获取服务器端传来的文件的大小(单位:byte)
    5. 由于输入不是纯数字,因此String不能顺利转换为int

    6. 解决方案:

           // 预定义
           bw = new BufferedWriter(new OutputStreamWriter(
                       socket.getOutputStream()));
           // 服务器端
           is = new FileInputStream(new File(BASE_PATH + fileName));
           byte[] b = new byte[is.available()];
           System.out.println(is.available());
           pw.println(is.available()); // 告诉客户端要接收的文件的大小(单位:byte)
           // 预定义
           br = new BufferedReader(new InputStreamReader(
                       socket.getInputStream()));
           // 客户端
           int length = Integer.parseInt(br.readLine()); // 获取服务器端传来的文件的大小(单位:byte)
           System.out.println("文件大小为:" + length + " bytes");
           byte[] b = new byte[length];
  2. 问题2:文件过大,不能一次传输完

    1. 问题描述:

    2. 网络编程——实验一:基于TCP&UDP的网络文件服务_第2张图片

    3. 解决方案:分段传输

    4. 代码如下:

           // 服务器端
           is = new FileInputStream(new File(BASE_PATH + fileName));
           pw.println(is.available()); // 告诉客户端要接收的文件的大小(单位:byte)
           byte[] b = new byte[BYTE_LEN];
           // 创建UDP数据报
           while (is.read(b) != -1) {
               DatagramPacket dp = new DatagramPacket(b, b.length, socketAddress);
               dgSocket.send(dp);
               System.out.println("传输文件中...");
               TimeUnit.MICROSECONDS.sleep(100); // 限制传输速度
           }
           System.out.println("文件发送成功");
           // 客户端
                   os = new FileOutputStream(new File(BASE_PATH + fileName));
                   byte[] b = new byte[BYTE_LEN];
                   DatagramPacket dp = new DatagramPacket(b, b.length);
                   
                   int length = Integer.parseInt(br.readLine()); // 获取服务器端传来的文件的大小(单位:byte)
                   while (length > 0) {
                       // 接收数据
                       dgSocket.receive(dp);
                       os.write(b, 0, b.length);
                       os.flush();
                       System.out.println("接收文件中...");
                       length -= BYTE_LEN;
                   }

       

  3. 问题3:文件名输入错误(系统在该目录下找不到该文件),未使用try catch语句捕捉错误

    1. 问题描述:

    2. 网络编程——实验一:基于TCP&UDP的网络文件服务_第3张图片

    3. 解决方案:

                   // 服务器端
                   try {
                       is = new FileInputStream(new File(BASE_PATH + fileName));
                   } catch(FileNotFoundException e) {
                       System.out.println("不存在该文件,取消文件传输");
                       pw.println("不存在该文件,取消文件传输");
                       e.printStackTrace();
                       return;
                   }
                   if( br.readLine().equals("不存在该文件,取消文件传输") ) {
                       System.out.println("取消文件传输,结束本次通信");
                       return;
                   } else {
                       System.out.println("文件已验证存在");
                   }
    4. 衍生问题:由于已经调用过一次br.readLine(),后面又通过br.readLine()获取文件长度。而readLine()会移动读取指针,且服务器端只传了一次length(通过pw.println(is.available());),因此在第二次调用br.readLine()的时候,客户端获取的内容为空,导致线程阻塞,文件传输不能正常进行。

      1. 解决方案:

                     // 预定义
                     PrintWriter pw = new PrintWriter(bw, true);
                     // 服务器端
                     // 传两次,因为客户端br.readLine()使用了两次【readLine()函数使用一次会移动读取指针】
                     pw.println(is.available()); // 告诉客户端要接收的文件的大小(单位:byte)
                     pw.println(is.available()); // 告诉客户端要接收的文件的大小(单位:byte)
                     // 预定义
                     BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                     // 客户端
                     if( br.readLine().equals("不存在该文件,取消文件传输") ) {
                         System.out.println("取消文件传输,结束本次通信");
                         return;
                     } else {
                         System.out.println("文件已验证存在");
                     }
                     int length = Integer.parseInt(br.readLine()); // 获取服务器端传来的文件的大小(单位:byte)
  4. 问题4:

 

3.1.2 客户端作为发送端,服务器端作为接收端

 

3.2 TCP文件传输

 

4 实现实验要求

 

3.1 简述实验要求

1) 复习Java I/O和Socket编程相关概念和方法;

2) 基于Java Socket TCP和UDP实现一个简易的网络文件服务程序,包含服务器端FileServer和客户端FileClient;

3) 服务器端启动时需传递root目录参数,并校验该目录是否有效;

4) 服务器启动后,开启TCP:2021端口,UDP:2020端口,其中,TCP连接负责与用户交互,UDP负责传送文件;

5) 客户端启动后,连接指定服务器的TCP 2021端口,成功后,服务器端回复信息:“客户端IP地址:客户端端口号>连接成功”;

6) 连接成功后,用户可通过客户端命令行执行以下命令:

*[1] ls* 服务器返回当前目录文件列表( name size)

*[2] cd * 进入指定目录(需判断目录是否存在,并给出提示)

*[3] get * 通过UDP下载指定文件,保存到客户端当前目录下

*[4] bye* 断开连接,客户端运行完毕

7) 服务器端支持多用户并发访问,不用考虑文件过大或UDP传输不可靠的问题。

 

3.2 创建TCP和UDP的服务器端

 

3.2 使用TCP传输用户命令,使用UDP传输文件

 

3.3 文件目录管理

你可能感兴趣的:(网络编程,java,网络编程)