IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 网络协议 -> Java-Socket编程基于TCP协议实现文件的下载 -> 正文阅读

[网络协议]Java-Socket编程基于TCP协议实现文件的下载

? ? ? ? 作为一个初学者,最近在开始学习Java语言,该说不说,学习一门编程语言确实是有点枯燥,哈哈哈哈。每天就是看视频,敲代码,反反复复,唉。所以为了增加点乐趣,写个小程序,总结下这两天学到的东西。

? ? ? ? 整个程序思路很简单,就是:客户端获取到服务端可下载的文件,选择其中一个进行下载。

? ? ? ? 实现过程:

? ? ? ? 服务端

? ? ? ? ? ? ? ? 1、获取指定文件夹下的所有文件对象(使用listFile),存入集合。

    /*递归获取服务端指定文件夹下所有可供下载的文件
     * 存到集合中,将此集合返回*/
    public static ArrayList<File> getFiles(File e) {
        File[] list = e.listFiles();
        for (File x : list) {
            if (x.isDirectory()) {
                getFiles(x);
            } else if (!x.isDirectory()) {
                fileList.add(x);
            }
        }
        return fileList;
    }

? ? ? ? ? ? ? ? 2、将集合序列化,存入本地,生成txt文件。

        ObjectOutputStream write = new ObjectOutputStream(new FileOutputStream("SocketPrj\\src\\FileDownLoad\\服务端配置文件.txt"));
        write.writeObject(fileList);    //序列化集合对象,将集合对象发送到客户端然后反序列化,然后展示可以下载的文件

? ? ? ? ? ? ? ? 3、将序列化后的文件发送至客户端,这样就可以每次运行程序,客户端就可以获取到最新的服务端可供下载的所有的文件。当然,这只是其中的一种实现方式,主要是想复习下序列化和反序列化。

        conSocket = serverSocket.accept();
        System.out.println("连接成功,开始发送文件列表...");
        OutputStream output = conSocket.getOutputStream();
        FileInputStream getSetFile = new FileInputStream("SocketPrj\\src\\FileDownLoad\\服务端配置文件.txt");   //准备读取集合序列化文件
        byte[] bt = new byte[1024];
        int len = 0;
        while ((len = getSetFile.read(bt)) != -1) {
            output.write(bt, 0, len);
        }
        conSocket.shutdownOutput();
        write.close();
        System.out.println("配置文件发送完成");

? ? ? ? ? ? ? ? 4、接收客户端请求下载的文件,然后向客户端发送指定的文件。

        fileSocket = serverSocket.accept();     //新开的负责文件发送的socket
        System.out.println("客户端选择下载的文件是:" + downLoadFileName + ",开始发送...");
        for (File x : fileList) {
            if (downLoadFileName.equals(x.getName())) {
                FileInputStream readFile = new FileInputStream(x);
                BufferedInputStream bfReader = new BufferedInputStream(readFile);   //读取将发送的本地文件
                OutputStream out = fileSocket.getOutputStream();
                byte[] bt = new byte[1024];     //设置每次发送数据的大小
                int len = 0;
                while ((len = bfReader.read(bt)) != -1) {
                    out.write(bt, 0, len);
                }
                fileSocket.shutdownOutput(); //通知客户端文件已发送完毕,关闭读取
                break;
            }
        }

? ? ? ? 客户端

? ? ? ? ? ? ? ? 1、反序列化服务端发来的txt文件,获取到可下载的文件对象并且展示到控制台。

        //本地配置文件,存储的是可供下载的文件对象
        FileOutputStream writeSetFile = new FileOutputStream("SocketPrj\\src\\FileDownLoad\\客户端配置文件.txt");
        //接收服务端发来的配置文件
        BufferedOutputStream bfWriterSetFile = new BufferedOutputStream(writeSetFile);
        conSocket = new Socket(InetAddress.getLocalHost(), 8848);
        System.out.println("连接成功,正在接收配置文件(文件集合)");
        InputStream in = conSocket.getInputStream();
        byte[] bt = new byte[1024];
        int len = 0;
        while ((len = in.read(bt)) != -1) {
            bfWriterSetFile.write(bt, 0, len);
            bfWriterSetFile.flush();
        }
        bfWriterSetFile.close();
        System.out.println("获取成功!");
        //返序列化文件,获取存储的文件对象
        ObjectInputStream getSetFiles = new ObjectInputStream(new FileInputStream("SocketPrj\\src\\FileDownLoad\\客户端配置文件.txt"));
        Object obj = getSetFiles.readObject();
        ArrayList<File> list = (ArrayList<File>) obj;
        getSetFiles.close();
        ArrayList<String> tempList = new ArrayList<>();
        System.out.println("服务器可供下载文件有:");
        for (File x : list) {
            tempList.add(x.getName());
            System.out.println(x.getName());
        }

? ? ? ? ? ? ? ? 2、根据展示内容选择要下载的文件,发送下载请求。

        /*接收用户输入的想下载的文件,输入不存在的文件名
         * 就会一直处于输入状态
         * 输入正确跳出循环
         * 正确后向服务端发送下载请求*/
        while (true) {
            System.out.print("输入你想下载的文件名:");
            str = new Scanner(System.in).nextLine();
            if (tempList.contains(str)) {
                System.out.println("输入正确,等待下载...");
                break;
            } else {
                System.out.println("你输入的文件不存在!请重新输入:");
            }
        }
        /*向服务器发送下载请求*/
        OutputStream out = conSocket.getOutputStream();
        out.write(str.getBytes());
        conSocket.shutdownOutput();
        System.out.println("请求发送成功,等待下载...");
        conSocket.close();

? ? ? ? ? ? ? ? 3、接收服务端发来的文件,存入本地文件夹。

        //因为第一个负责通信的socket使用了shutdownOutput,导致无法使用其继续发送数据
        //所以新开一个socket专门负责发文件
        fileSocket = new Socket(InetAddress.getLocalHost(), 8848);
        System.out.println("开始下载文件...");
        FileOutputStream writer = new FileOutputStream("SocketPrj\\ClientFiles\\" + str);
        InputStream in = fileSocket.getInputStream();
        byte[] bt = new byte[1024];
        int len;
        while ((len = in.read(bt)) != -1) {
            writer.write(bt, 0, len);
        }
        System.out.println("下载成功!");

服务端完整代码:

package FileDownLoad;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
/*文件下载之服务端
 * 作者:小刘同学
 * 时间:2021年10月21日 23点28分
 * 目的:复习巩固下socket编程
 * */
public class ServerAllFiles extends Thread {
    static ArrayList<File> fileList = new ArrayList<>();        //存储可供下载文件对象的集合
    static ServerSocket serverSocket;   //服务端Socket,建立监听对象
    static String downLoadFileName = null;  //接收客户端发过来的文件名
    static Socket conSocket = null;     //负责和客户端通信的socket
    static Socket fileSocket = null;    //接收文件的socket

    public static void main(String[] args) throws IOException, InterruptedException {
        ServerAllFiles th = new ServerAllFiles();
        th.start();
    }

    @Override
    public void run() {
        File allFiles = new File("SocketPrj\\ServerAllFiles");
        getFiles(allFiles);
        try {
            sendSetFile();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /*递归获取服务端指定文件夹下所有可供下载的文件
     * 存到集合中,将此集合返回*/
    public static ArrayList<File> getFiles(File e) {
        File[] list = e.listFiles();
        for (File x : list) {
            if (x.isDirectory()) {
                getFiles(x);
            } else if (!x.isDirectory()) {
                fileList.add(x);
            }
        }
        return fileList;
    }

    /*发送配置文件(里面装的是可供下载文件的名字)*/
    public static void sendSetFile() throws IOException, InterruptedException {
        ObjectOutputStream write = new ObjectOutputStream(new FileOutputStream("SocketPrj\\src\\FileDownLoad\\服务端配置文件.txt"));
        write.writeObject(fileList);    //序列化集合对象,将集合对象发送到客户端然后反序列化,然后展示可以下载的文件
        System.out.println("列表更新完成");
        serverSocket = new ServerSocket(8848);
        System.out.println("正在等待客户端连接...");

        conSocket = serverSocket.accept();
        System.out.println("连接成功,开始发送文件列表...");
        OutputStream output = conSocket.getOutputStream();
        FileInputStream getSetFile = new FileInputStream("SocketPrj\\src\\FileDownLoad\\服务端配置文件.txt");   //准备读取集合序列化文件
        byte[] bt = new byte[1024];
        int len = 0;
        while ((len = getSetFile.read(bt)) != -1) {
            output.write(bt, 0, len);
        }
        conSocket.shutdownOutput();
        write.close();
        System.out.println("配置文件发送完成");
        System.out.println("等待接收下载请求...");
        InputStream in = conSocket.getInputStream();
        byte[] btRecive = new byte[1024];
        int lenRecive = 0;
        downLoadFileName = null;     //接收客户端发过来的下载文件名
        while ((lenRecive = in.read(btRecive)) != -1) {
            downLoadFileName = new String(btRecive, 0, lenRecive);
        }
        conSocket.close();
        recivePost();
    }

    /*接收客户端下载请求
     * 发送文件*/
    public static void recivePost() throws IOException {
        fileSocket = serverSocket.accept();     //新开的负责文件发送的socket
        System.out.println("客户端选择下载的文件是:" + downLoadFileName + ",开始发送...");
        for (File x : fileList) {
            if (downLoadFileName.equals(x.getName())) {
                FileInputStream readFile = new FileInputStream(x);
                BufferedInputStream bfReader = new BufferedInputStream(readFile);   //读取将发送的本地文件
                OutputStream out = fileSocket.getOutputStream();
                byte[] bt = new byte[1024];     //设置每次发送数据的大小
                int len = 0;
                while ((len = bfReader.read(bt)) != -1) {
                    out.write(bt, 0, len);
                }
                fileSocket.shutdownOutput(); //通知客户端文件已发送完毕,关闭读取
                break;
            }
        }
        System.out.println("发送完成,客户端已接收到文件!");
    }
}

客户端完整代码

package FileDownLoad;
import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Scanner;

public class ClientDownCls extends Thread {
    /*文件下载之客户端
     * 作者:小刘同学
     * 时间2021年10月21日 23点28分
     * 目的:复习巩固下socket编程
     * */
    static Socket conSocket;
    static Socket fileSocket;
    static String str = null;

    public static void main(String[] args) throws IOException, ClassNotFoundException {
        ClientDownCls client = new ClientDownCls();
        client.start();
    }

    @Override
    public void run() {
        try {
            getSetFile();   //其中包含展示可下载的文件列表,以及下载文件
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    /*接收服务端传过来的配置文件(文件集合)*/
    public static void getSetFile() throws IOException, ClassNotFoundException {
        //本地配置文件,存储的是可供下载的文件对象
        FileOutputStream writeSetFile = new FileOutputStream("SocketPrj\\src\\FileDownLoad\\客户端配置文件.txt");
        //接收服务端发来的配置文件
        BufferedOutputStream bfWriterSetFile = new BufferedOutputStream(writeSetFile);
        conSocket = new Socket(InetAddress.getLocalHost(), 8848);
        System.out.println("连接成功,正在接收配置文件(文件集合)");
        InputStream in = conSocket.getInputStream();
        byte[] bt = new byte[1024];
        int len = 0;
        while ((len = in.read(bt)) != -1) {
            bfWriterSetFile.write(bt, 0, len);
            bfWriterSetFile.flush();
        }
        bfWriterSetFile.close();
        System.out.println("获取成功!");
        getList();
    }

    /*读取配置文件,获取集合对象
     * 选择下载文件,将用户选择的下载的文件的请求发回服务器
     * */
    public static void getList() throws IOException, ClassNotFoundException {
        //返序列化文件,获取存储的文件对象
        ObjectInputStream getSetFiles = new ObjectInputStream(new FileInputStream("SocketPrj\\src\\FileDownLoad\\客户端配置文件.txt"));
        Object obj = getSetFiles.readObject();
        ArrayList<File> list = (ArrayList<File>) obj;
        getSetFiles.close();
        ArrayList<String> tempList = new ArrayList<>();
        System.out.println("服务器可供下载文件有:");
        for (File x : list) {
            tempList.add(x.getName());
            System.out.println(x.getName());
        }
        System.out.println("==================================");   //华丽的的分割线
        /*接收用户输入的想下载的文件,输入不存在的文件名
         * 就会一直处于输入状态
         * 输入正确跳出循环
         * 正确后向服务端发送下载请求*/
        while (true) {
            System.out.print("输入你想下载的文件名:");
            str = new Scanner(System.in).nextLine();
            if (tempList.contains(str)) {
                System.out.println("输入正确,等待下载...");
                break;
            } else {
                System.out.println("你输入的文件不存在!请重新输入:");
            }
        }
        /*向服务器发送下载请求*/
        OutputStream out = conSocket.getOutputStream();
        out.write(str.getBytes());
        conSocket.shutdownOutput();
        System.out.println("请求发送成功,等待下载...");
        conSocket.close();
        downFile();
    }

    /*接收服务端发来的文件*/
    public static void downFile() throws IOException {
        //因为第一个负责通信的socket使用了shutdownOutput,导致无法使用其继续发送数据
        //所以新开一个socket专门负责发文件
        fileSocket = new Socket(InetAddress.getLocalHost(), 8848);
        System.out.println("开始下载文件...");
        FileOutputStream writer = new FileOutputStream("SocketPrj\\ClientFiles\\" + str);
        InputStream in = fileSocket.getInputStream();
        byte[] bt = new byte[1024];
        int len;
        while ((len = in.read(bt)) != -1) {
            writer.write(bt, 0, len);
        }
        System.out.println("下载成功!");
    }
}

运行截图:

?

?

总结一句话就是:服务端,读出来-发出去 | 客户端,接收到,写进去

????????我觉得其中有一个值得需注意的问题,就是需要对socket对象使用shutdownOutput方法,不使用这个方法,又会出现程序阻塞,有小伙伴知道阻塞原因吗?(嘿嘿嘿)。不过使用后就无法继续使用该socket对象发送数据,一时想不到解决办法,想的就是只有重新创建一个socket负责发送数据。但是感觉这样不妥,于是百度了下,好像这也算是一种解决办法,其他方法倒是没找到。不知道还有没有其他更好的方法。

? ? ? ? 最后,不用知道为啥心血来潮,想写这篇博客,也算是第一个文章,哈哈哈哈,可能主要是向纪念下吧。当然,程序很简单,也有很多问题,还请大家不吝赐教。完整代码贴在上面了,有需要的小伙伴可以参考下哦,大家一起加油,冲冲冲

  网络协议 最新文章
使用Easyswoole 搭建简单的Websoket服务
常见的数据通信方式有哪些?
Openssl 1024bit RSA算法---公私钥获取和处
HTTPS协议的密钥交换流程
《小白WEB安全入门》03. 漏洞篇
HttpRunner4.x 安装与使用
2021-07-04
手写RPC学习笔记
K8S高可用版本部署
mySQL计算IP地址范围
上一篇文章      下一篇文章      查看所有文章
加:2021-10-23 12:49:51  更:2021-10-23 12:51:07 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年7日历 -2024/7/3 13:35:30-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码