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

javasocket断点下载_java大文件下载+断点续传

java两台服务器之间,大文件上传(续传),采用了Socket通信机制以及JavaIO流两个技术点,具体思路如下:实现思路&

java两台服务器之间,大文件上传(续传),采用了Socket通信机制以及JavaIO流两个技术点,具体思路如下:

实现思路:

1、服:利用ServerSocket搭建服务器,开启相应端口,进行长连接操作

2、服:使用ServerSocket.accept()方法进行阻塞,接收客户端请求

3、服:每接收到一个Socket就建立一个新的线程来处理它

4、客:利用Socket进行远程连接,询问已上传进度

5、客:使用FileInputStream.skip(long length)从指定位置读取文件,向服务器发送文件流

6、服:接收客户端输入流,使用RandomAccessFile.seek(long length)随机读取,将游标移动到指定位置进行读写

7、客/服:一个循环输出,一个循环读取写入

8、示例:以下是具体代码,仅供参考

文件介绍:

FileUpLoadServer.java(服务器接收文件类)

FileUpLoadClient.java(客户端发送文件类)

FinalVariables.java(自定义参数类)

SocketServerListener.java(JavaWeb启动Socket操作类)

web.xml(配置文件,跟随项目启动)

断点上传(服务端)

package com.cn.csdn.seesun2012.socket;

import java.io.DataInputStream;

import java.io.DataOutputStream;

import java.io.File;

import java.io.FileOutputStream;

import java.io.IOException;

import java.io.RandomAccessFile;

import java.math.RoundingMode;

import java.net.ServerSocket;

import java.net.Socket;

import java.text.DecimalFormat;

public class FileUpLoadServer extends ServerSocket {

// 文件大小

private static DecimalFormat df = null;

// 退出标识

private boolean quit = false;

static {

// 设置数字格式,保留一位有效小数

df = new DecimalFormat("#0.0");

df.setRoundingMode(RoundingMode.HALF_UP);

df.setMinimumFractionDigits(1);

df.setMaximumFractionDigits(1);

}

public FileUpLoadServer(int report) throws IOException {

super(report);

}

/**

* 使用线程处理每个客户端传输的文件

*

* @throws Exception

*/

public void load() throws Exception {

System.out.println("【文件上传】服务器:" + this.getInetAddress() + " 正在运行中...");

while (!quit) {

// server尝试接收其他Socket的连接请求,server的accept方法是阻塞式的

Socket socket = this.accept();

/**

* 我们的服务端处理客户端的连接请求是同步进行的, 每次接收到来自客户端的连接请求后,

* 都要先跟当前的客户端通信完之后才能再处理下一个连接请求。 这在并发比较多的情况下会严重影响程序的性能,

* 为此,我们可以把它改为如下这种异步处理与客户端通信的方式

*/

// 收到请求,验证合法性

String ip = socket.getInetAddress().toString();

ip = ip.substring(1, ip.length());

System.out.println("服务器接收到请求,正在开启验证对方合法性IP:" + ip + "!");

// 每接收到一个Socket就建立一个新的线程来处理它

new Thread(new Task(socket, ip)).start();

}

}

/**

* 处理客户端传输过来的文件线程类

*/

class Task implements Runnable {

private Socket sk;// 当前连接

private String ips; // 当前连接IP址

public Task(Socket socket, String ip) {

this.sk = socket;

this.ips = ip;

}

public void run() {

Socket socket = sk;// 重新定义,请不要移出run()方法外部,否则连接两会被重置

String ip = ips;// 重新定义,同上IP会变

long serverLength = -1l;// 定义:存放在服务器里的文件长度,默认没有为-1

char pathChar = File.separatorChar;// 获取:系统路径分隔符

String panFu = "D:";// 路径:存储文件盘符

DataInputStream dis = null;// 获取:客户端输出流

DataOutputStream dos = null;// 发送:向客户端输入流

FileOutputStream fos = null;// 读取:服务器本地文件流

RandomAccessFile rantmpfile = null;// 操作类:随机读取

try {

// 获取

dis = new DataInputStream(socket.getInputStream());

// 发送

dos = new DataOutputStream(socket.getOutputStream());

// 定义客户端传过来的文件名

String fileName = "";

while (fileName == "") {

// 读取客户端传来的数据

fileName = dis.readUTF();

System.out.println("服务器获取客户端文件名称:" + fileName);

File file = new File(panFu+ pathChar +"receive"+ pathChar +"" + ip + pathChar + fileName);

if (file.exists()) {

serverLength = file.length();

dos.writeLong(serverLength);

System.out.println("向客户端返回文件长度:" + serverLength + " B");

} else {

serverLength = 0l;

dos.writeLong(serverLength);

System.out.println("文件不存在");

System.out.println("向客户端返回文件长度:" + serverLength + " B");

}

}

System.out.println("服务器建立新线程处理客户端请求,对方IP:" + ip + ",传输正在进行中...");

// 从客户端获取输入流

dis = new DataInputStream(socket.getInputStream());

// 文件名和长度

long fileLength = dis.readLong();

File directory = new File(panFu + pathChar + "receive"+ pathChar +"" + ip + pathChar);

if (!directory.exists()) {

directory.mkdirs();

}

int length = 0;

byte[] bytes = new byte[1024];

File file = new File(directory.getAbsolutePath() + pathChar + fileName);

if (!file.exists()) {

// 不存在

fos = new FileOutputStream(file);

// 开始接收文件

while ((length = dis.read(bytes, 0, bytes.length)) != -1) {

fos.write(bytes, 0, length);

fos.flush();

}

} else {

// 存储在服务器中的文件长度

long fileSize = file.length(), pointSize = 0;

// 判断是否已下载完成

if (fileLength > fileSize) {

// 断点下载

pointSize = fileSize;

} else {

// 重新下载

file.delete();

file.createNewFile();

}

rantmpfile = new RandomAccessFile(file, "rw");

/*

* java.io.InputStream.skip() 用法:跳过 n 个字节(丢弃) 如果 n

* 为负,则不跳过任何字节。

*/

// dis.skip(pointSize); (已从客户端读取进度)

/**

* 资源,文件定位(游标、指针) 将ras的指针设置到8,则读写ras是从第9个字节读写到

*/

rantmpfile.seek(pointSize);

while ((length = dis.read(bytes, 0, bytes.length)) != -1) {

rantmpfile.write(bytes, 0, length);

}

}

System.out.println("======== 文件接收成功 [File Name:" + fileName + "] [ClientIP:" + ip + "] [Size:" + getFormatFileSize(file.length()) + "] ========");

} catch (Exception e) {

e.printStackTrace();

} finally {

try {

if (fos != null)

fos.close();

if (dis != null)

dis.close();

if (rantmpfile != null)

rantmpfile.close();

socket.close();

} catch (Exception e) {

e.printStackTrace();

System.out.println("Socket关闭失败!");

}

/**

* 文件传输完毕:执行后续操作(略)

*/

//DoSomeThing dst = new DoSomeThing()

//dst.save(filePath);

}

}

}

/**

* 格式化文件大小

*

* @param length

* @return

*/

public String getFormatFileSize(long length) {

double size &#61; ((double) length) / (1 <<30);

if (size >&#61; 1) {

return df.format(size) &#43; "GB";

}

size &#61; ((double) length) / (1 <<20);

if (size >&#61; 1) {

return df.format(size) &#43; "MB";

}

size &#61; ((double) length) / (1 <<10);

if (size >&#61; 1) {

return df.format(size) &#43; "KB";

}

return length &#43; "B";

}

/**

* 退出

*/

public void quit() {

this.quit &#61; true;

try {

this.close();

} catch (IOException e) {

System.out.println("服务器关闭发生异常&#xff0c;原因未知");

}

}

}

断点上传(客户端)

package com.cn.csdn.seesun2012.socket;

import java.io.DataInputStream;

import java.io.DataOutputStream;

import java.io.File;

import java.io.FileInputStream;

import java.io.FileNotFoundException;

import java.io.IOException;

import java.net.Socket;

import java.net.UnknownHostException;

import java.util.Timer;

import java.util.TimerTask;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

/**

* Client端

* 功能说明&#xff1a;文件上传(断点)传输

*

* &#64;author CSDN:seesun2012

* &#64;CreateDate 2017年08月18日

* &#64;Override2017年11月07日

* &#64;version 1.1

*/

public class FileUpLoadClient extends Socket{

private Logger logger &#61; LoggerFactory.getLogger("oaLogger");

private Socket client;// Socket-客户端

private static long status &#61; 0;// 进度条

private boolean quit &#61; false;//退出

/**

* 构造器

*

* &#64;param ip服务端IP地址

* &#64;param report服务端开放的端口

* &#64;throws UnknownHostException

* &#64;throws IOException

*/

public FileUpLoadClient(String ip, Integer report) throws UnknownHostException, IOException {

super(ip, report);

this.client &#61; this;

if (client.getLocalPort()>0) {

System.out.println("Cliect[port:" &#43; client.getLocalPort() &#43; "] 成功连接服务端");

}else{

System.out.println("服务器连接失败");

}

}

public int sendFile(String filePath) {

DataOutputStream dos &#61; null;// 上传服务器&#xff1a;输出流

DataInputStream dis &#61; null;// 获取服务器&#xff1a;输入流

Long serverLength &#61; -1l;// 存储在服务器的文件长度&#xff0c;默认-1

FileInputStream fis &#61; null;// 读取文件&#xff1a;输入流

// 获取&#xff1a;上传文件

File file &#61; new File(filePath);

// &#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61; 节点&#xff1a;文件是否存在 &#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;

if (file.exists()) {

//发送&#xff1a;文件名称、文件长度

try {

dos &#61; new DataOutputStream(client.getOutputStream());

} catch (IOException e2) {

logger.error("Socket客户端&#xff1a;1.读取输出流发生错误");

e2.printStackTrace();

}

try {

dos.writeUTF(file.getName());

dos.flush();

dos.writeLong(file.length());

dos.flush();

} catch (IOException e2) {

logger.error("Socket客户端&#xff1a;2.向服务器发送文件名、长度发生错误");

e2.printStackTrace();

}

// 获取&#xff1a;已上传文件长度

try {

dis &#61; new DataInputStream(client.getInputStream());

} catch (IOException e2) {

logger.error("Socket客户端&#xff1a;3.向服务器发送文件名、长度发生错误");

e2.printStackTrace();

}

while(serverLength&#61;&#61;-1){

try {

serverLength &#61; dis.readLong();

} catch (IOException e) {

logger.error("Socket客户端&#xff1a;4.读取服务端长度发送错误");

e.printStackTrace();

}

}

// 读取&#xff1a;需要上传的文件

try {

fis &#61; new FileInputStream(file);

} catch (FileNotFoundException e2) {

logger.error("Socket客户端&#xff1a;5.读取本地需要上传的文件失败&#xff0c;请确认文件是否存在");

e2.printStackTrace();

}

// 发送&#xff1a;向服务器传输输入流

try {

dos &#61; new DataOutputStream(client.getOutputStream());

} catch (IOException e2) {

logger.error("Socket客户端&#xff1a;6.向服务器传输输入流发生错误");

e2.printStackTrace();

}

System.out.println("&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61; 开始传输文件 &#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;");

byte[] bytes &#61; new byte[1024];

int length &#61; 1024;

long progress &#61; serverLength;

// 设置游标&#xff1a;文件读取的位置

if (serverLength&#61;&#61;-1l) {

serverLength &#61; 0l;

}

try {

fis.skip(serverLength);

} catch (IOException e1) {

logger.error("Socket客户端&#xff1a;7.设置游标位置发生错误&#xff0c;请确认文件流是否被篡改");

e1.printStackTrace();

}

try {

while (((length &#61; fis.read(bytes, 0, bytes.length)) !&#61; -1) && quit !&#61; true) {

dos.write(bytes, 0, length);

dos.flush();

progress &#43;&#61; length;

status &#61; (100 * progress / file.length());

}

} catch (IOException e) {

logger.error("Socket客户端&#xff1a;8.设置游标位置发生错误&#xff0c;请确认文件流是否被篡改");

e.printStackTrace();

}finally {

if (fis !&#61; null)

try {

fis.close();

} catch (IOException e1) {

logger.error("Socket客户端&#xff1a;9.关闭读取的输入流异常");

e1.printStackTrace();

}

if (dos !&#61; null)

try {

dos.close();

} catch (IOException e1) {

logger.error("Socket客户端&#xff1a;10.关闭发送的输出流异常");

e1.printStackTrace();

}

try {

client.close();

} catch (IOException e) {

logger.error("Socket客户端&#xff1a;11.关闭客户端异常");

e.printStackTrace();

}

}

System.out.println("&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61; 文件传输成功 &#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;");

}else{

logger.error("Socket客户端&#xff1a;0.文件不存在");

return -1;

}

return 1;

}

/**

* 进度条

*/

public void statusInfo(){

Timer time &#61; new Timer();

time.schedule(new TimerTask() {

long num &#61; 0;

&#64;Override

public void run() {

if (status>num) {

System.out.println("当前进度为&#xff1a;"&#43;status&#43;"%");

num &#61; status;

}

if (status&#61;&#61;101) {

System.gc();

}

}

},0,100);

}

/**

* 退出

*/

public void quit() {

this.quit &#61; true;

try {

this.close();

} catch (IOException e) {

System.out.println("服务器关闭发生异常&#xff0c;原因未知");

}

}

}

断点上传(参数设置)

package com.cn.csdn.seesun2012.socket;

public interface FinalVariables {

// 服务端IP

public final static String SERVER_IP &#61; "192.168.1.10010";

// 服务端端口

public final static int SERVER_PORT &#61; 10086;

// 开启配置

public final static String IS_START_SERVER &#61; "instart";

}

断点上传(JavaWeb启动服务端)

package com.cn.csdn.seesun2012.socket;

import java.util.Timer;

import java.util.TimerTask;

import javax.servlet.ServletException;

import javax.servlet.http.HttpServlet;

/**

* Server端

* 功能说明&#xff1a;服务端监听开启Servlet

*

* &#64;author CSDN:seesun2012

* &#64;CreateDate 2017年08月18日

* &#64;Override2017年11月07日

* &#64;Override2017年11月14日

* &#64;version 1.3

*/

public class SocketServerListener extends HttpServlet{

private static final long serialVersionUID &#61; -999999999999999999L;

// 初始化启动Socket服务

&#64;Override

public void init() throws ServletException {

super.init();

for(int i &#61; 0; i <3; i&#43;&#43;){

if ("instart".equals(FinalVariables.IS_START_SERVER )) {

open();

break;

}

}

}

public void open(){

Timer timer &#61; new Timer();

timer.schedule(new TimerTask() {

&#64;SuppressWarnings("resource")

&#64;Override

public void run() {

try {

FileUpLoadServer fileUpLoadServer &#61; new FileUpLoadServer(FinalVariables.SERVER_PORT);

fileUpLoadServer.load();

} catch (Exception e) {

e.printStackTrace();

}

}

}, 3000);

}

}

web.xml配置(跟随项目启动)

index.html

index.jsp

SocketServerListener

com.cn.csdn.seesun2012.socket.SocketServerListener

10

seesun2012

功能展示截图&#xff1a;

在页面中选择好相应的上传目录&#xff0c;点击粘贴上传按钮&#xff0c;数据即可快速开始上传&#xff0c;电脑重启后打开网页也可以按当前进度继续上传

002bcc7802af0dda0a165877aaa86ad1.png

文件和目录下载

批量下载 同时选择多个需要下载的文件 然后点击下载按钮&#xff0c;设置下载目录文件夹

077af6f953a013bffdae197bcc122994.png



推荐阅读
  • 在JavaWeb开发中,文件上传是一个常见的需求。无论是通过表单还是其他方式上传文件,都必须使用POST请求。前端部分通常采用HTML表单来实现文件选择和提交功能。后端则利用Apache Commons FileUpload库来处理上传的文件,该库提供了强大的文件解析和存储能力,能够高效地处理各种文件类型。此外,为了提高系统的安全性和稳定性,还需要对上传文件的大小、格式等进行严格的校验和限制。 ... [详细]
  • Linux CentOS 7 安装PostgreSQL 9.5.17 (源码编译)
    近日需要将PostgreSQL数据库从Windows中迁移到Linux中,LinuxCentOS7安装PostgreSQL9.5.17安装过程特此记录。安装环境&#x ... [详细]
  • 本文介绍了如何利用 `matplotlib` 库中的 `FuncAnimation` 类将 Python 中的动态图像保存为视频文件。通过详细解释 `FuncAnimation` 类的参数和方法,文章提供了多种实用技巧,帮助用户高效地生成高质量的动态图像视频。此外,还探讨了不同视频编码器的选择及其对输出文件质量的影响,为读者提供了全面的技术指导。 ... [详细]
  • 如何在Linux服务器上配置MySQL和Tomcat的开机自动启动
    在Linux服务器上部署Web项目时,通常需要确保MySQL和Tomcat服务能够随系统启动而自动运行。本文将详细介绍如何在Linux环境中配置MySQL和Tomcat的开机自启动,以确保服务的稳定性和可靠性。通过合理的配置,可以有效避免因服务未启动而导致的项目故障。 ... [详细]
  • 本文介绍了如何使用 Node.js 和 Express(4.x 及以上版本)构建高效的文件上传功能。通过引入 `multer` 中间件,可以轻松实现文件上传。首先,需要通过 `npm install multer` 安装该中间件。接着,在 Express 应用中配置 `multer`,以处理多部分表单数据。本文详细讲解了 `multer` 的基本用法和高级配置,帮助开发者快速搭建稳定可靠的文件上传服务。 ... [详细]
  • `chkconfig` 命令主要用于管理和查询系统服务在不同运行级别中的启动状态。该命令不仅能够更新服务的启动配置,还能检查特定服务的当前状态。通过 `chkconfig`,管理员可以轻松地控制服务在系统启动时的行为,确保关键服务正常运行,同时禁用不必要的服务以提高系统性能和安全性。本文将详细介绍 `chkconfig` 的各项参数及其使用方法,帮助读者更好地理解和应用这一强大的系统管理工具。 ... [详细]
  • Ihavetwomethodsofgeneratingmdistinctrandomnumbersintherange[0..n-1]我有两种方法在范围[0.n-1]中生 ... [详细]
  • ### 优化后的摘要本学习指南旨在帮助读者全面掌握 Bootstrap 前端框架的核心知识点与实战技巧。内容涵盖基础入门、核心功能和高级应用。第一章通过一个简单的“Hello World”示例,介绍 Bootstrap 的基本用法和快速上手方法。第二章深入探讨 Bootstrap 与 JSP 集成的细节,揭示两者结合的优势和应用场景。第三章则进一步讲解 Bootstrap 的高级特性,如响应式设计和组件定制,为开发者提供全方位的技术支持。 ... [详细]
  • 本文详细介绍了在CentOS 6.5 64位系统上使用阿里云ECS服务器搭建LAMP环境的具体步骤。首先,通过PuTTY工具实现远程连接至服务器。接着,检查当前系统的磁盘空间使用情况,确保有足够的空间进行后续操作,可使用 `df` 命令进行查看。此外,文章还涵盖了安装和配置Apache、MySQL和PHP的相关步骤,以及常见问题的解决方法,帮助用户顺利完成LAMP环境的搭建。 ... [详细]
  • 体积小巧的vsftpd与pureftpd Docker镜像在Unraid系统中的详细配置指南:支持TLS加密及IPv6协议
    本文详细介绍了如何在Unraid系统中配置体积小巧的vsftpd和Pure-FTPd Docker镜像,以支持TLS加密和IPv6协议。通过这些配置,用户可以实现安全、高效的文件传输服务,适用于各种网络环境。配置过程包括镜像的选择、环境变量的设置以及必要的安全措施,确保了系统的稳定性和数据的安全性。 ... [详细]
  • 利用 Python Socket 实现 ICMP 协议下的网络通信
    在计算机网络课程的2.1实验中,学生需要通过Python Socket编程实现一种基于ICMP协议的网络通信功能。与操作系统自带的Ping命令类似,该实验要求学生开发一个简化的、非标准的ICMP通信程序,以加深对ICMP协议及其在网络通信中的应用的理解。通过这一实验,学生将掌握如何使用Python Socket库来构建和解析ICMP数据包,并实现基本的网络探测功能。 ... [详细]
  • 深入解析 OpenSSL 生成 SM2 证书:非对称加密技术与数字证书、数字签名的关联分析
    本文深入探讨了 OpenSSL 在生成 SM2 证书过程中的技术细节,重点分析了非对称加密技术在数字证书和数字签名中的应用。非对称加密通过使用公钥和私钥对数据进行加解密,确保了信息传输的安全性。公钥可以公开分发,用于加密数据或验证签名,而私钥则需严格保密,用于解密数据或生成签名。文章详细介绍了 OpenSSL 如何利用这些原理生成 SM2 证书,并讨论了其在实际应用中的安全性和有效性。 ... [详细]
  • Presto:高效即席查询引擎的深度解析与应用
    本文深入解析了Presto这一高效的即席查询引擎,详细探讨了其架构设计及其优缺点。Presto通过内存到内存的数据处理方式,显著提升了查询性能,相比传统的MapReduce查询,不仅减少了数据传输的延迟,还提高了查询的准确性和效率。然而,Presto在大规模数据处理和容错机制方面仍存在一定的局限性。本文还介绍了Presto在实际应用中的多种场景,展示了其在大数据分析领域的强大潜力。 ... [详细]
  • AppFog 是一个基于 CloudFoundry 的多语言 PaaS(平台即服务)提供商,允许用户在其平台上轻松构建和部署 Web 应用程序。本文将通过详细的图文步骤,指导读者如何在 AppFog 免费云平台上成功部署 WordPress,帮助用户快速搭建个人博客或网站。 ... [详细]
  • 在Unity中进行3D建模的全面指南,详细介绍了市场上三种主要的3D建模工具:Blender 3D、Maya和3ds Max。每种工具的特点、优势及其在Unity开发中的应用将被深入探讨,帮助开发者选择最适合自己的建模软件。 ... [详细]
author-avatar
手机用户2502852635_269
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有