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. git 添加本地项目到远程仓库 记录一下命令

    1.初始化 git init 2.关联远程仓库 git remote add origin 你的仓库地址 3.加入到本地仓库 git add * 4.推送(强推).如果不想强推 ,可以先执行下 git ...

  2. 【0.3】mysql复制的日常管理维护,mysql复制常见问题处理

    [1]复制的日常管理 #复制的日常管理与维护 [1.1]show slave status\G :在从库查看从库线程状态 [1.2]flush tables with read lock;  :主从不 ...

  3. 算法 - k-means算法

    一.聚类思想 所谓聚类算法是指将一堆没有标签的数据自动划分成几类的方法,属于无监督学习方法,这个方法要保证同一类的数据有相似的特征,如下图所示:     根据样本之间的距离或者说是相似性(亲疏性),把 ...

  4. 爬取糗事百科热门段子的数据并保存到本地,xpath的使用

    和之前的爬虫类博客的爬取思路基本一致: 构造url_list,因为糗事百科的热门栏目默认是13页,所以这个就简单了 遍历发送请求获取响应 提取数据,这里用的是xpath提取,用的是Python的第三方 ...

  5. Python和其他编程语言

    Python和其他编程语言 一.Python介绍 Python的创始人为吉多·范罗苏姆(Guido van Rossum),如下图,少数几个不秃头的语言创始人.1989年的圣诞节期间,Guido为了打 ...

  6. TCP socket 编程

    TCP socket 编程 讲一下 socket 编程 步骤 使用 socket 模块 建立 TCP socket 客户端和服务端 客户端和服务端之间的通信 图解 编程 举个例子 tcp_server ...

  7. monggoDB添加到windows服务

    ----------------mongoDB安装------------------------------- 1.下载mongoDB安装包安装完毕后,配置环境变量 D:\Program Files ...

  8. 剑指offer-左旋转字符串-知识迁移能力-python

    题目描述汇编语言中有一种移位指令叫做循环左移(ROL),现在有个简单的任务,就是用字符串模拟这个指令的运算结果.对于一个给定的字符序列S,请你把其循环左移K位后的序列输出.例如,字符序列S=”abcX ...

  9. vs nuget找不到包

    nuget.org https://api.nuget.org/v3/index.json

  10. 配置maven的国内镜像

    pom.xml文件出现错误标记,一般是相关的maven资源没有下载完整. 1,配置maven的国内镜像,保证能够顺利下载maven中配置的资源. 在maven的配置文件  settings.xml  ...