热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

java网络编程怎样实现文件传输?

设计一个简单的文件传输程序,服务器接受文件,客户端发送文件,设计一个简单的文件传输协议,比如,先传输文件名,再传输文件大小,再传输文件内容。设计不合理。一个文件信息,不需要分成几个

设计一个简单的文件传输程序,服务器接受文件,客户端发送文件,设计一个简单的文件传输协议,比如,先传输文件名,再传输文件大小,再传输文件内容。

《java网络编程怎样实现文件传输?》

设计不合理。
一个文件信息,不需要分成几个包来来回回请求应答。
协议格式类似如下:
8位数据包总长+3位文件名长度+文件名+ 8位文件内容长度+文件内容
以上为变长报文格式,举例如下:
00001048+008+test.txt+00001024+文件内容

要么像2L所定义的协议那样发送,简单
要么就像你期望的那样,定义协议位 数据长度(固定长度)+数据类型(固定长度)+数据
第一次传文件名 比如8位长度(String.format(“%08d”, filename.getBytes().length).getByes())+数据类型(”01″.getBytes())+数据(filename.getBytes())
第二次传文件大小 8位长度+数据类型(”02″)+file.getLength()
第三次以后 8位长度+数据类型(”03″)+file.read(buf) //最后要check和第二次传送的文件长度一致

如果是基于tcp的长连接进行传输,最好先把文件名、文件大小等文件信息进行加密传输,然后再传输实际的文件流,这样接收方可以先解密文件报文,再取根据报文内容来解析文件流。这样一是可以保证文件安全,排除非法文件传输,二是可以让接收方有据可依。

怎么用多线程完成这个任务啊

这个问题,相当于一个问题终结者。资源代下载99dxz

楼主的协议太墨迹了,我写了一个简单的demo,和楼主共同探讨一下。
我觉得没有必要多次交互,服务端只需要被动的接受就好了。
如果需要交互行为的话,服务端和客户端的编程模式就会复杂一些,建议使用netty进行开发。

这个是服务端的demo,接收一个文件。

package houlei.net.tcp;

 

 

import java.io.*;

import java.net.ServerSocket;

import java.net.Socket;

import java.nio.charset.Charset;

import java.text.SimpleDateFormat;

import java.util.Date;

import java.util.LinkedList;

 

public class FileServer {

 

    private final File tmpPath;

    private final File targetPath;

    private final int port;

    private final LinkedList workers = new LinkedList();

    private ServerSocket serverSocket;

    private class Worker extends Thread {

        private final Socket socket;

 

        private Worker(Socket socket) {

            this.socket = socket;

        }

 

        public void run(){

            try {

                InputStream is = socket.getInputStream();

                byte[] nameLen = new byte[4];

                if (is.read(nameLen) == 4) {

                    int nameLength = (nameLen[0]&0xFF)<<24 | (nameLen[1]&0xFF)<<16 | (nameLen[2]&0xFF)<<8  | (nameLen[3]&0xFF)<<0;

                    byte[] name = new byte[nameLength];

                    if (nameLength == is.read(name)) {

                        String fileName = new String(name, Charset.forName("UTF-8"));

                        byte[] length = new byte[8];

                        if (is.read(length) == 8) {

                            long fileLength = (length[0]&0xFF)<<56 | (length[1]&0xFF)<<48 | (length[2]&0xFF)<<40 | (length[3]&0xFF)<<32 |

                                    (length[4]&0xFF)<<24 | (length[5]&0xFF)<<16 | (length[6]&0xFF)<<8  | (length[7]&0xFF)<<0;

                            readFile(fileName, fileLength, is);

                        }

                    }

                }

 

            catch (Exception ex) {

                ex.printStackTrace();

            finally {

                try {

                    socket.close();

                catch (IOException e) {

                    e.printStackTrace();

                }

                workers.remove(Worker.this);

                System.out.println("bye : "+socket.getRemoteSocketAddress());

            }

        }

 

        private void readFile(String fileName, long fileLength, InputStream is) throws IOException {

            String prefix = "trans-" new SimpleDateFormat("yyyyMMddHHmmssSSS").format(new Date());

            if (tmpPath.getUsableSpace() > fileLength && targetPath.getUsableSpace() > fileLength) {

                File tempFile = File.createTempFile(prefix, "tmp", tmpPath);

                OutputStream os = new FileOutputStream(tempFile);

                transform(os, is);

                os.close();

                File targetFile = new File(targetPath, fileName);

                if (tempFile.renameTo(targetFile)) {

                    // succeed.

                }

            }

        }

 

        private void transform(OutputStream os, InputStream is) throws IOException {

            byte[] buffer = new byte[4096];

            int length = 0;

            while((length = is.read(buffer))>0) {

                os.write(buffer, 0, length);

            }

            os.flush();

        }

    }

 

    public FileServer(File tmpPath, File targetPath, int port) {

        if (tmpPath == null) {

            tmpPath = new File(System.getProperty("java.io.tmpdir"));

        }

        if (!tmpPath.exists()) {

            tmpPath.mkdirs();

        }

        if (targetPath == null || !targetPath.exists()) {

            throw new IllegalArgumentException("targetPath does not exists.");

        }

        this.tmpPath = tmpPath;

        this.targetPath = targetPath;

        this.port = port;

    }

 

    public void start() throws IOException {

        if (serverSocket == null) {

            serverSocket = new ServerSocket(port);

            Socket socket;

            while((socket = serverSocket.accept()) != null) {

                System.out.println("accept : "+ socket.getRemoteSocketAddress());

                Worker worker = new Worker(socket);

                workers.add(worker);

                worker.start();

            }

        }

    }

 

    public static void main(String[] args) throws IOException {

        File targetFolder = new File("/Users/naver/target");

        targetFolder.mkdirs();

        FileServer server = new FileServer(null, targetFolder, 6606);

        server.start();

    }

}

这个是客户端的demo,和服务端配合,将客户端的文件传输到服务端。

package houlei.net.tcp;

 

 

import java.io.*;

import java.net.Socket;

import java.nio.charset.Charset;

 

public class FileClient {

 

    private final String serverIp;

    private final int serverPort;

    private Socket socket;

 

    public FileClient(String serverIp, int serverPort) {

        this.serverIp = serverIp;

        this.serverPort = serverPort;

    }

 

    public void connect() throws IOException {

        if (socket == null) {

            socket = new Socket(serverIp, serverPort);

        }

    }

 

    public void sendFile(File file) throws IOException {

        if (!file.exists() || !file.isFile()) {

            throw new IllegalArgumentException("file ("+file.getName()+") does not exists.");

        }

        String fileName = file.getName();

        long fileLength = file.length();

        InputStream inputStream = new FileInputStream(file);

        sendFile(fileName, fileLength, inputStream);

    }

 

    private void sendFile(String fileName, long fileLength, InputStream inputStream) throws IOException {

        byte[] name = fileName.getBytes(Charset.forName("UTF-8"));

        byte[] nameLen = new byte[4];

        nameLen[0] = (byte) ((name.length>>>24)&0xFF);nameLen[1] = (byte) ((name.length>>>16)&0xFF);

        nameLen[2] = (byte) ((name.length>>> 8)&0xFF);nameLen[3] = (byte) ((name.length>>> 0)&0xFF);

        byte[] length = new byte[8];

        length[0] = (byte) ((fileLength>>>56)&0xFF);length[1] = (byte) ((fileLength>>>48)&0xFF);

        length[2] = (byte) ((fileLength>>>40)&0xFF);length[3] = (byte) ((fileLength>>>32)&0xFF);

        length[4] = (byte) ((fileLength>>>24)&0xFF);length[5] = (byte) ((fileLength>>>16)&0xFF);

        length[6] = (byte) ((fileLength>>> 8)&0xFF);length[7] = (byte) ((fileLength>>> 0)&0xFF);

        if (socket.isConnected()) {

            OutputStream os = socket.getOutputStream();

            os.write(nameLen);

            os.write(name);

            os.write(length);

            os.flush();

            transform(os, inputStream);

        }

    }

 

    private void transform(OutputStream os, InputStream is) throws IOException {

        byte[] buffer = new byte[4096];

        int length = 0;

        while((length = is.read(buffer))>0) {

            os.write(buffer, 0, length);

        }

        os.flush();

    }

 

 

    public static void main(String[] args) throws IOException {

        FileClient client = new FileClient("127.0.0.1"6606);

        client.connect();

        client.sendFile(new File("/Users/naver/helper.js"));

    }

}

 


推荐阅读
  • 图解redis的持久化存储机制RDB和AOF的原理和优缺点
    本文通过图解的方式介绍了redis的持久化存储机制RDB和AOF的原理和优缺点。RDB是将redis内存中的数据保存为快照文件,恢复速度较快但不支持拉链式快照。AOF是将操作日志保存到磁盘,实时存储数据但恢复速度较慢。文章详细分析了两种机制的优缺点,帮助读者更好地理解redis的持久化存储策略。 ... [详细]
  • Java序列化对象传给PHP的方法及原理解析
    本文介绍了Java序列化对象传给PHP的方法及原理,包括Java对象传递的方式、序列化的方式、PHP中的序列化用法介绍、Java是否能反序列化PHP的数据、Java序列化的原理以及解决Java序列化中的问题。同时还解释了序列化的概念和作用,以及代码执行序列化所需要的权限。最后指出,序列化会将对象实例的所有字段都进行序列化,使得数据能够被表示为实例的序列化数据,但只有能够解释该格式的代码才能够确定数据的内容。 ... [详细]
  • Centos7.6安装Gitlab教程及注意事项
    本文介绍了在Centos7.6系统下安装Gitlab的详细教程,并提供了一些注意事项。教程包括查看系统版本、安装必要的软件包、配置防火墙等步骤。同时,还强调了使用阿里云服务器时的特殊配置需求,以及建议至少4GB的可用RAM来运行GitLab。 ... [详细]
  • Mac OS 升级到11.2.2 Eclipse打不开了,报错Failed to create the Java Virtual Machine
    本文介绍了在Mac OS升级到11.2.2版本后,使用Eclipse打开时出现报错Failed to create the Java Virtual Machine的问题,并提供了解决方法。 ... [详细]
  • t-io 2.0.0发布-法网天眼第一版的回顾和更新说明
    本文回顾了t-io 1.x版本的工程结构和性能数据,并介绍了t-io在码云上的成绩和用户反馈。同时,还提到了@openSeLi同学发布的t-io 30W长连接并发压力测试报告。最后,详细介绍了t-io 2.0.0版本的更新内容,包括更简洁的使用方式和内置的httpsession功能。 ... [详细]
  • 本文介绍了Hyperledger Fabric外部链码构建与运行的相关知识,包括在Hyperledger Fabric 2.0版本之前链码构建和运行的困难性,外部构建模式的实现原理以及外部构建和运行API的使用方法。通过本文的介绍,读者可以了解到如何利用外部构建和运行的方式来实现链码的构建和运行,并且不再受限于特定的语言和部署环境。 ... [详细]
  • 本文介绍了PhysioNet网站提供的生理信号处理工具箱WFDB Toolbox for Matlab的安装和使用方法。通过下载并添加到Matlab路径中或直接在Matlab中输入相关内容,即可完成安装。该工具箱提供了一系列函数,可以方便地处理生理信号数据。详细的安装和使用方法可以参考本文内容。 ... [详细]
  • 本文介绍了Perl的测试框架Test::Base,它是一个数据驱动的测试框架,可以自动进行单元测试,省去手工编写测试程序的麻烦。与Test::More完全兼容,使用方法简单。以plural函数为例,展示了Test::Base的使用方法。 ... [详细]
  • sklearn数据集库中的常用数据集类型介绍
    本文介绍了sklearn数据集库中常用的数据集类型,包括玩具数据集和样本生成器。其中详细介绍了波士顿房价数据集,包含了波士顿506处房屋的13种不同特征以及房屋价格,适用于回归任务。 ... [详细]
  • 计算机存储系统的层次结构及其优势
    本文介绍了计算机存储系统的层次结构,包括高速缓存、主存储器和辅助存储器三个层次。通过分层存储数据可以提高程序的执行效率。计算机存储系统的层次结构将各种不同存储容量、存取速度和价格的存储器有机组合成整体,形成可寻址存储空间比主存储器空间大得多的存储整体。由于辅助存储器容量大、价格低,使得整体存储系统的平均价格降低。同时,高速缓存的存取速度可以和CPU的工作速度相匹配,进一步提高程序执行效率。 ... [详细]
  • 本文介绍了Web学习历程记录中关于Tomcat的基本概念和配置。首先解释了Web静态Web资源和动态Web资源的概念,以及C/S架构和B/S架构的区别。然后介绍了常见的Web服务器,包括Weblogic、WebSphere和Tomcat。接着详细讲解了Tomcat的虚拟主机、web应用和虚拟路径映射的概念和配置过程。最后简要介绍了http协议的作用。本文内容详实,适合初学者了解Tomcat的基础知识。 ... [详细]
  • 本文介绍了计算机网络的定义和通信流程,包括客户端编译文件、二进制转换、三层路由设备等。同时,还介绍了计算机网络中常用的关键词,如MAC地址和IP地址。 ... [详细]
  • 如何在服务器主机上实现文件共享的方法和工具
    本文介绍了在服务器主机上实现文件共享的方法和工具,包括Linux主机和Windows主机的文件传输方式,Web运维和FTP/SFTP客户端运维两种方式,以及使用WinSCP工具将文件上传至Linux云服务器的操作方法。此外,还介绍了在迁移过程中需要安装迁移Agent并输入目的端服务器所在华为云的AK/SK,以及主机迁移服务会收集的源端服务器信息。 ... [详细]
  • [大整数乘法] java代码实现
    本文介绍了使用java代码实现大整数乘法的过程,同时也涉及到大整数加法和大整数减法的计算方法。通过分治算法来提高计算效率,并对算法的时间复杂度进行了研究。详细代码实现请参考文章链接。 ... [详细]
  • 本文介绍了在mac环境下使用nginx配置nodejs代理服务器的步骤,包括安装nginx、创建目录和文件、配置代理的域名和日志记录等。 ... [详细]
author-avatar
wgsd325
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有