• 《互联网程序设计》 -- 第4周网络文件的传输


    这周是学习,设计一个网络文件传输程序

    总述

    文件传输协议规定(RFC 959),网络文件传输中用两个TCP端口来实现:

    一个端口(21号)用来对话,传递控制信息,总是开启;

     一个端口(20号)实现文件数据传递服务,有数据传输服务时开启。

    网络对话和网络文件传输,使用TCPsocket编程,本质还是一样,对话过程,使用字符流来包装;而网络文件传输过程,则应该使用字节流来进行处理。

    再说一遍,两者本质一样!

    都是客户端向服务器发送请求,服务器判断,当服务器接收到的是下载文件的请求的时候就会调用方法吧文件(可封装成其他类型)写入网络流中,然后客户端就接收这个文件。本质还是一样的。

    设计第一步:创建窗体界面

     如图所示,与前几周的窗体大致相似。增加了下载按钮

    下载按钮的功能:

    btnDownload.setOnAction(event -> {
      if(tfSend.getText().equals("")) //没有输入文件名则返回
        return;
    
    
      String fName = tfSend.getText().trim();
      tfSend.clear();
    
      FileChooser fileChooser = new FileChooser();
      fileChooser.setInitialFileName(fName);
      File saveFile = fileChooser.showSaveDialog(null);
      if (saveFile == null) {
        return;//用户放弃操作则返回
      }  
      try {
        //数据端口是2020
        new FileDataClient(ip, "2020").getFile(saveFile);
        Alert alert = new Alert(Alert.AlertType.INFORMATION);
        alert.setContentText(saveFile.getName() + " 下载完毕!");
        alert.showAndWait();
        //通知服务器已经完成了下载动作,不发送的话,服务器不能提供有效反馈信息
        fileDialogClient.send("客户端开启下载");
      } catch (IOException e) {
        e.printStackTrace();
      }
    });
    Download按钮

    还有一种锦上添花的功能,实现鼠标拖拽就能复制内容到信息输入框:

    //信息显示区鼠标拖动高亮文字直接复制到信息输入框,方便选择文件名
    //taDispaly为信息选择区的TextArea,tfSend为信息输入区的TextField
    //为taDisplay的选择范围属性添加监听器,当该属性值变化(选择文字时),会触发监听器中的代码
    taDisplay.selectionProperty().addListener((observable, oldValue, newValue) -> {
      //只有当鼠标拖动选中了文字才复制内容
      if(!taDisplay.getSelectedText().equals(""))
        tfSend.setText(taDisplay.getSelectedText());
    });

    设计第二步,创建客户端数据传输程序

    我们应该想到这个程序应该有的功能:连接服务器数据端口、发送文件名、保存下载的文件,文件传输完成后关闭数据连接。

    我们可以在构造方法中向服务器发起连接

    public FileDataClient(String ip,String port) throws IOException{
            dataSocket = new Socket(ip, Integer.parseInt(port));//服务器发起连接
    
        }

    剩下的功能我们可以封装成一个getFile方法:

    public void getFile(File saveFile) throws IOException {
    
            if (dataSocket != null) { // dataSocket是Socket类型的成员变量
    
    
                FileOutputStream fileOut = new FileOutputStream(saveFile);//新建本地空文件
                byte[] buf = new byte[1024]; // 用来缓存接收的字节数据
                //网络字节输入流
                InputStream socketIn = dataSocket.getInputStream();
                //网络字节输出流
                OutputStream socketOut = dataSocket.getOutputStream();
    
                //(2)向服务器发送请求的文件名,字符串读写功能
                PrintWriter pw = new PrintWriter(new OutputStreamWriter(socketOut, "utf-8"), true);
                pw.println(saveFile.getName());
    
                //(3)接收服务器的数据文件,字节读写功能
                int size = 0;
                while ((size = socketIn.read(buf)) != -1) {//读一块到缓存,读取结束返回-1
                    fileOut.write(buf, 0, size); //写一块到文件
                }
                fileOut.flush();//关闭前将缓存的数据全部推出
                //文件传输完毕,关闭流
                fileOut.close();
                if (dataSocket != null) {
                    dataSocket.close();
                }
            } else {
                System.err.println("连接ftp数据服务器失败");
            }
        }
    getFile方法

    众所周知,下载文件是一个交互的过程。

    所以我们需要在一些关键的时间点提醒用户,或者说提示。如:文件开始下载时,完成下载时:

    这里就是创建了一个对话框用来提示用户:

    new FileDataClient(ip, "2020").getFile(saveFile);//数据端口为2020
        Alert alert = new Alert(Alert.AlertType.INFORMATION);
        alert.setContentText(saveFile.getName() + " 下载完毕!");
        alert.showAndWait();
        //通知服务器已经完成了下载动作,不发送的话,服务器不能提供有效反馈信息
        fileDialogClient.send("客户端开启下载");

    这样我们的一个简易的网络文件传输程序就设计完成了。

    实验中注意的点是在 把ip,port这两个成员变量使用的时候,不能将他们重新在连接按钮那里重新定义,不然ip和port的值就是null了。

    错误示范:

     正确如下:

    或者直接把获得ip和port的方法放在类里面而非方法里。

    本次的所有代码都放在:https://wws.lanzous.com/ivMzch0al7a

    认清现实,放弃幻想。 细节决定成败,心态放好,认真学习与工作。
  • 相关阅读:
    简单小巧的跨平台共享内存代码
    调试发行版程序 (二)
    休息日公园独步偶得
    Minimum Depth of Binary Tree
    LeetCode Length of Last word
    黑书 折纸痕 uva 177
    Palindrome Partitioning II leetcode
    Acumem ThreadSpotter
    C++ string int 转换 split
    Valid Palindrome Leetcode
  • 原文地址:https://www.cnblogs.com/jyf2018/p/13746840.html
Copyright © 2020-2023  润新知