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;

publicclass FileUpLoadServer extends ServerSocket {

// 文件大小

privatestatic DecimalFormat df =null;

// 退出标识

privateboolean 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

*/

publicvoid 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;

}

publicvoid 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 =newbyte[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 =((double) length)/(1<<30);

if(size >=1){

return df.format(size)+"GB";

}

size =((double) length)/(1<<20);

if(size >=1){

return df.format(size)+"MB";

}

size =((double) length)/(1<<10);

if(size >=1){

return df.format(size)+"KB";

}

return length +"B";

}

/**

* 退出

*/

publicvoid quit(){

this.quit =true;

try{

this.close();

}catch(IOException e){

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

}

}

}

断点上传(客户端)

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端<br><br>

* 功能说明:文件上传(断点)传输

*

* @author CSDN:seesun2012

* @CreateDate 2017年08月18日

* @Override    2017年11月07日

* @version 1.1

*/

publicclass FileUpLoadClient extends Socket{

private Logger logger = LoggerFactory.getLogger("oaLogger");

private Socket client;   // Socket-客户端

privatestaticlong status =0;    // 进度条

privateboolean quit =false;     //退出

/**

* 构造器

*

* @param ip   服务端IP地址

* @param report    服务端开放的端口

* @throws UnknownHostException

* @throws IOException

*/

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

super(ip, report);

this.client =this;

if(client.getLocalPort()>0){

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

}else{

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

}

}

publicint sendFile(String filePath){

DataOutputStream dos =null;// 上传服务器:输出流

DataInputStream dis =null;  // 获取服务器:输入流

Long serverLength =-1l;// 存储在服务器的文件长度,默认-1

FileInputStream fis =null;  // 读取文件:输入流

// 获取:上传文件

File file =new File(filePath);

// ==================== 节点:文件是否存在 ====================

if(file.exists()){

//   发送:文件名称、文件长度

try{

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

}catch(IOException e2){

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

e2.printStackTrace();

}

try{

dos.writeUTF(file.getName());

dos.flush();

dos.writeLong(file.length());

dos.flush();

}catch(IOException e2){

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

e2.printStackTrace();

}

// 获取:已上传文件长度

try{

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

}catch(IOException e2){

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

e2.printStackTrace();

}

while(serverLength==-1){

try{

serverLength = dis.readLong();

}catch(IOException e){

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

e.printStackTrace();

}

}

// 读取:需要上传的文件

try{

fis =new FileInputStream(file);

}catch(FileNotFoundException e2){

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

e2.printStackTrace();

}

// 发送:向服务器传输输入流

try{

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

}catch(IOException e2){

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

e2.printStackTrace();

}

System.out.println("======== 开始传输文件 ========");

byte[] bytes =newbyte[1024];

int length =1024;

long progress = serverLength;

// 设置游标:文件读取的位置

if(serverLength==-1l){

serverLength =0l;

}

try{

fis.skip(serverLength);

}catch(IOException e1){

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

e1.printStackTrace();

}

try{

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

dos.write(bytes,0, length);

dos.flush();

progress += length;

status =(100* progress / file.length());

}

}catch(IOException e){

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

e.printStackTrace();

}finally{

if(fis !=null)

try{

fis.close();

}catch(IOException e1){

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

e1.printStackTrace();

}

if(dos !=null)

try{

dos.close();

}catch(IOException e1){

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

e1.printStackTrace();

}

try{

client.close();

}catch(IOException e){

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

e.printStackTrace();

}

}

System.out.println("======== 文件传输成功 ========");

}else{

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

return-1;

}

return1;

}

/**

* 进度条

*/

publicvoid statusInfo(){

Timer time =new Timer();

time.schedule(new TimerTask(){

long num =0;

@Override

publicvoid run(){

if(status>num){

System.out.println("当前进度为:"+status+"%");

num = status;

}

if(status==101){

System.gc();

}

}

},0,100);

}

/**

* 退出

*/

publicvoid quit(){

this.quit =true;

try{

this.close();

}catch(IOException e){

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

}

}

}

断点上传(参数设置)

package com.cn.csdn.seesun2012.socket;

publicinterface FinalVariables {

// 服务端IP

publicfinalstatic String SERVER_IP ="192.168.1.10010";

// 服务端端口

publicfinalstaticint SERVER_PORT =10086;

// 开启配置

publicfinalstatic String IS_START_SERVER ="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端<br><br>

* 功能说明:服务端监听开启Servlet

*

* @author CSDN:seesun2012

* @CreateDate 2017年08月18日

* @Override    2017年11月07日

* @Override    2017年11月14日

* @version 1.3

*/

publicclass SocketServerListener extends HttpServlet{

privatestaticfinallong serialVersionUID =-999999999999999999L;

// 初始化启动Socket服务

@Override

publicvoid init()throws ServletException {

super.init();

for(int i =0; i <3; i++){

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

open();

break;

}

}

}

publicvoid open(){

Timer timer =new Timer();

timer.schedule(new TimerTask(){

@SuppressWarnings("resource")

@Override

publicvoid run(){

try{

FileUpLoadServer fileUpLoadServer =new FileUpLoadServer(FinalVariables.SERVER_PORT);

fileUpLoadServer.load();

}catch(Exception e){

e.printStackTrace();

}

}

},3000);

}

}

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

<?xmlversion="1.0"encoding="UTF-8"?>

<web-app>

<welcome-file-list>

<welcome-file>index.html</welcome-file>

<welcome-file>index.jsp</welcome-file>

</welcome-file-list>

<servlet>

<servlet-name>SocketServerListener</servlet-name>

<servlet-class>com.cn.csdn.seesun2012.socket.SocketServerListener</servlet-class>

<load-on-startup>10</load-on-startup>

</servlet>

<display-name>seesun2012</display-name>

</web-app>

目前能够支持MySQL,Oracle,SQL。在使用前需要配置一下数据库,可以参考我写的这篇文章:http://blog.ncmem.com/wordpress/2019/08/12/java-http%E5%A4%A7%E6%96%87%E4%BB%B6%E6%96%AD%E7%82%B9%E7%BB%AD%E4%BC%A0%E4%B8%8A%E4%BC%A0/

java支持断点续传文件上传和下载组件的更多相关文章

  1. java实现大文件上传和下载

    [文件上传和下载]是很多系统必备功能, 比如PM\OA\ERP等:系统中常见的开发模式有B/S和C/S,而前者主要是通过浏览器来访问web服务器,一般采用七层协议中的[应用层http]进行数据传输,后 ...

  2. Java实现FTP文件上传与下载

    实现FTP文件上传与下载可以通过以下两种种方式实现(不知道还有没有其他方式),分别为:1.通过JDK自带的API实现:2.通过Apache提供的API是实现. 第一种方式 package com.cl ...

  3. 【Java】JavaWeb文件上传和下载

    文件上传和下载在web应用中非常普遍,要在jsp环境中实现文件上传功能是非常容易的,因为网上有许多用java开发的文件上传组件,本文以commons-fileupload组件为例,为jsp应用添加文件 ...

  4. Java Web(十一) 文件上传与下载

    文件上传 上传的准备工作 表单method必须为post 提供file组件 设置form标签的enctype属性为multipart/form-data,如果没有设置enctype属性,浏览器是无法将 ...

  5. java web(四)文件上传与下载

     一.文件上传原理 1.在TCP/IP中,最早出现的文件上传机制是FTP ,它是将文件由客户端发送到服务器的标准机制:但是在jsp使用过程中不能使用FTP方法上传文件,这是由jsp运行机制所决定. 通 ...

  6. Java中的文件上传和下载

    文件上传原理: 早期的文件上传机制: 在TCP/IP中.最早出现的文件上传机制是FTP.他是将文件由客户端发送到服务器的标准机制. jsp中的文件上传机制: 在jsp编程中不能使用FTP的方法来上传文 ...

  7. Java 实现ftp 文件上传、下载和删除

    本文利用apache ftp工具实现文件的上传下载和删除.具体如下: 1.下载相应的jar包 commons-net-1.4.1.jar 2.实现代码如下: public class FtpUtils ...

  8. java基础篇---文件上传(commons-FileUpload组件)

    上一篇讲解了smartupload组件上传,那么这一篇我们讲解commons-FileUpload组件上传 FileUpload是Apache组织(www.apache.org)提供的免费的上传组件, ...

  9. springboot+web文件上传和下载

    一.首先安装mysql数据库,开启web服务器. 二.pom.xml文件依赖包配置如下: <?xml version="1.0" encoding="UTF-8&q ...

随机推荐

  1. JavaRMI框架

     RMI(即Remote Method Invoke 远程方法调用).在Java中,只要一个类extends了java.rmi.Remote接口,即可成为存在于服务器端的远程对象,供客户端访问并提供一 ...

  2. Windows 系统安装 Docker

    详细方法参见官方文档. Win10 家庭版 安装Toolbox Win10 家庭版由于功能限制,不能直接安装 Docker for Windows, 需要使用 Toolbox 的形式进行安装. 确认版 ...

  3. JMX jconsole 的使用

    JMX 1. JMX简单介绍 JMX的全称为Java Management Extensions. 顾名思义,是管理Java的一种扩展.这种机制可以方便的管理正在运行中的Java程序.常用于管理线程, ...

  4. Java服务,内存OOM问题如何快速定位? (转)

    转自:公众号  架构师之路 问题:有一个Java服务出现了OOM(Out Of Memory)问题,定位了好久不得其法,请问有什么好的思路么? OOM的问题,印象中之前写过,这里再总结一些相对通用的方 ...

  5. linux centos 安装jdk

    1.先查看是否已经安装的有java java -version,如果有需要卸载的直接卸载      rpm -qa | grep java 下面这几个可以删除       java-1.7.0-ope ...

  6. Spark运行时的内核架构以及架构思考

    一: Spark内核架构 1,Drive是运行程序的时候有main方法,并且会创建SparkContext对象,是程序运行调度的中心,向Master注册程序,然后Master分配资源. 应用程序: A ...

  7. Docker 环境下部署 redash

    环境: centos7 官网:https://redash.io/help/open-source/dev-guide/docker 一.安装步骤 1.虚拟机安装 安装vmware,并安装centos ...

  8. ubuntu 创建定时备份pg数据库定时任务

    ubuntu创建定时备份数据库定时任务 一.命令文件 创建db_back.sh #!/bin/bash echo "start backup" /usr/lib/postgresq ...

  9. LeetCode——等差数列划分

    题目: 如果一个数列至少有三个元素,并且任意两个相邻元素之差相同,则称该数列为等差数列. 例如,以下数列为等差数列: 1, 3, 5, 7, 97, 7, 7, 73, -1, -5, -9 以下数列 ...

  10. 26、Nginx Uwsgi代理

    1.Uwsgi代理基本概述 cgi.fastcgi.wsgi.uwsgi python框架 Django是一个开放源代码的web的框架 Flask是一个使用python编写的轻量级web应用框架 2 ...