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
=
((
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”
;
}
/**
* 退出
*/
public void 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
*/
public class FileUpLoadClient
extends
Socket
{
private Logger logger
=
LoggerFactory
.
getLogger
(
“oaLogger”
);
private Socket client
;
// Socket-客户端
private static long status
=
0
;
// 进度条
private boolean 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
(
“服务器连接失败”
);
}
}
public int 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
=
new
byte
[
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
;
}
return
1
;
}
/**
* 进度条
*/
public void statusInfo
(){
Timer time
=
new
Timer
();
time
.
schedule
(
new
TimerTask
()
{
long num
=
0
;
@Override
public void run
()
{
if
(
status
>
num
)
{
System
.
out
.
println
(
“当前进度为:”
+
status
+
“%”
);
num
=
status
;
}
if
(
status
==
101
)
{
System
.
gc
();
}
}
},
0
,
100
);
}
/**
* 退出
*/
public void quit
()
{
this
.
quit
=
true
;
try
{
this
.
close
();
}
catch
(
IOException e
)
{
System
.
out
.
println
(
“服务器关闭发生异常,原因未知”
);
}
}
}
断点上传(参数设置)
package com
.
cn
.
csdn
.
seesun2012
.
socket
;
public interface FinalVariables
{
// 服务端IP
public final static String SERVER_IP
=
“192.168.1.10010”
;
// 服务端端口
public final static int SERVER_PORT
=
10086
;
// 开启配置
public final static 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
*/
public class SocketServerListener
extends
HttpServlet
{
private static final long serialVersionUID
=
–
999999999999999999L
;
// 初始化启动Socket服务
@Override
public void init
()
throws
ServletException
{
super
.
init
();
for
(
int i
=
0
;
i
<
3
;
i
++){
if
(
“instart”
.
equals
(
FinalVariables
.
IS_START_SERVER
))
{
open
();
break
;
}
}
}
public void open
(){
Timer timer
=
new
Timer
();
timer
.
schedule
(
new
TimerTask
()
{
@SuppressWarnings
(
“resource”
)
@Override
public void run
()
{
try
{
FileUpLoadServer fileUpLoadServer
=
new
FileUpLoadServer
(
FinalVariables
.
SERVER_PORT
);
fileUpLoadServer
.
load
();
}
catch
(
Exception e
)
{
e
.
printStackTrace
();
}
}
},
3000
);
}
}
web.xml配置(跟随项目启动)
<?xml version=
“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。在使用前需要配置一下数据库
效果展示:
视频演示:
Web大文件上传下载-jsp-springboot-mysql-示例
windows控件安装
,,
linux-deb控件包安装
,
linux-rpm控件包安装
,
php7测试
,
php5测试
,
vue-cli-测试
,
asp.net-IIS测试
,
asp.net-阿里云(oss)测试
,
asp.net-华为云(obs)测试
,
jsp-springboot测试
,
ActiveX(x86)源码编译
,
ActiveX(x64)源码编译
,
Windows(npapi)源码编译
,
macOS源码编译
,
Linux(x86_64)源码编译
,
Linux(arm)源码编译
,
Linux(mips-uos)源码编译
,
Linux(mips-kylin-涉密环境)源码编译
,
sm4加密传输
,
压缩传输
,
示例下载地址
asp.net源码下载
,
jsp-springboot源码下载
,
jsp-eclipse源码下载
,
jsp-myeclipse源码下载
,
php源码下载
,
csharp-winform源码下载
,
vue-cli源码下载
,
c++源码下载