本实例只是简单地实现文件的断点上传功能,有更好的建议请不吝赐教
本实例基于html5的 websocket API和netty框架,如果您对两个技术不太熟悉,可以点击下面连接了解
websocket: http://www.chinaz.com/web/2012/0806/267188.shtml
netty: https://netty.io/
netty jar包:http://download.csdn.net/detail/wudasong_/4650052
准备:
fiefox浏览器或chrome浏览器
在classpath中导入netty类库,json类库
好拉,一切准备就绪...
服务器端:
WebSocketServerInitializer.java
/*
* Copyright 2012 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package com.wudasong.breakPoinUploadServer;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.socket.nio.NioEventLoop;
import io.netty.channel.socket.nio.NioServerSocketChannel;
/**
* A HTTP server which serves Web Socket requests at:
*
* http://localhost:8080/websocket
*
* Open your browser at http://localhost:8080/, then the demo page will be loaded and a Web Socket connection will be
* made automatically.
*
* This server illustrates support for the different web socket specification versions and will work with:
*
* <ul>
* <li>Safari 5+ (draft-ietf-hybi-thewebsocketprotocol-00)
* <li>Chrome 6-13 (draft-ietf-hybi-thewebsocketprotocol-00)
* <li>Chrome 14+ (draft-ietf-hybi-thewebsocketprotocol-10)
* <li>Chrome 16+ (RFC 6455 aka draft-ietf-hybi-thewebsocketprotocol-17)
* <li>Firefox 7+ (draft-ietf-hybi-thewebsocketprotocol-10)
* <li>Firefox 11+ (RFC 6455 aka draft-ietf-hybi-thewebsocketprotocol-17)
* </ul>
*/
public class WebSocketServer {
private final int port;
public WebSocketServer(int port) {
this.port = port;
}
public void run() throws Exception {
ServerBootstrap b = new ServerBootstrap();
try {
b.eventLoop(new NioEventLoop(), new NioEventLoop())
.channel(new NioServerSocketChannel())
.localAddress(port)
.childHandler(new WebSocketServerInitializer());
Channel ch = b.bind().sync().channel();
System.out.println("Web socket server started at port " + port + '.');
System.out.println("Open your browser and navigate to http://localhost:" + port + '/');
ch.closeFuture().sync();
} finally {
b.shutdown();
}
}
public static void main(String[] args) throws Exception {
int port;
if (args.length > 0) {
port = Integer.parseInt(args[0]);
} else {
port = 8082;
}
new WebSocketServer(port).run();
}
}
WebSocketServerHandler.java
package com.wudasong.breakPoinUploadServer;
import static io.netty.handler.codec.http.HttpHeaders.*;
import static io.netty.handler.codec.http.HttpHeaders.Names.CONTENT_TYPE;
import static io.netty.handler.codec.http.HttpMethod.*;
import static io.netty.handler.codec.http.HttpResponseStatus.*;
import static io.netty.handler.codec.http.HttpVersion.*;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import org.json.JSONException;
import org.json.JSONObject;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundMessageHandlerAdapter;
import io.netty.handler.codec.http.DefaultHttpResponse;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.HttpResponse;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame;
import io.netty.handler.codec.http.websocketx.CloseWebSocketFrame;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketServerHandshaker;
import io.netty.handler.codec.http.websocketx.WebSocketServerHandshakerFactory;
import io.netty.util.CharsetUtil;
/**
* Handles handshakes and messages
*/
public class WebSocketServerHandler extends ChannelInboundMessageHandlerAdapter<Object> {
private static final String WEBSOCKET_PATH = "/websocket";
private static final long BLOCK_SIZE=1024*65L;
private static final int BYTE_BUFFER_SIZE=1024*65;
private static final String SERVER_SAVE_PATH="D:\\fileUpload\\";
private long startByte=0;
private long stopByte=0;
private JSONObject fileInfo;
private WebSocketServerHandshaker handshaker;
@Override
public void messageReceived(ChannelHandlerContext ctx, Object msg) throws Exception {
if (msg instanceof HttpRequest) {
handleHttpRequest(ctx, (HttpRequest) msg);
} else if (msg instanceof WebSocketFrame) {
handleWebSocketFrame(ctx, (WebSocketFrame) msg);
}
}
private void handleHttpRequest(ChannelHandlerContext ctx, HttpRequest req) throws Exception {
// Allow only GET methods.
if (req.getMethod() != GET) {
sendHttpResponse(ctx, req, new DefaultHttpResponse(HTTP_1_1, FORBIDDEN));
return;
}
// Handshake
WebSocketServerHandshakerFactory wsFactory = new WebSocketServerHandshakerFactory(
getWebSocketLocation(req), null, false,1048576);
handshaker = wsFactory.newHandshaker(req);
if (handshaker == null) {
wsFactory.sendUnsupportedWebSocketVersionResponse(ctx.channel());
} else {
handshaker.handshake(ctx.channel(), req);
}
}
private void handleWebSocketFrame(ChannelHandlerContext ctx, WebSocketFrame frame) throws JSONException, IOException {
// Check for closing frame
if (frame instanceof CloseWebSocketFrame) {
handshaker.close(ctx.channel(), (CloseWebSocketFrame) frame);
return;
} else if(frame instanceof TextWebSocketFrame){
TextWebSocketFrame message=(TextWebSocketFrame)frame;
fileInfo=new JSONObject(message.getText());
System.out.println("上传的文件名:\t"+fileInfo.getString("name")+
"\n文件大小:\t"+fileInfo.getLong("size")+
"\n最后修改时间:\t"+fileInfo.getString("lastModifiedDate"));
JSONObject message4client=new JSONObject();
File file = new File(SERVER_SAVE_PATH+fileInfo.getString("name"));
long fileSize=fileInfo.getLong("size");
if(file.createNewFile()){
stopByte=BLOCK_SIZE;
message4client.put("startByte", 0);
if(stopByte<fileSize){
message4client.put("stopByte", stopByte);
}else {
message4client.put("stopByte", fileSize);
}
message4client.put("complete", false);
}else {
startByte=file.length();
stopByte=startByte+BLOCK_SIZE;
if(startByte>=fileInfo.getLong("size")){
message4client.put("startByte", 0);
message4client.put("stopByte", 0);
message4client.put("complete", true);
}
if(stopByte<fileSize){
message4client.put("startByte", startByte);
message4client.put("stopByte", stopByte);
message4client.put("complete", false);
}else {
message4client.put("startByte", startByte);
message4client.put("stopByte", fileSize);
message4client.put("complete", false);
}
}
ctx.channel().write(new TextWebSocketFrame(message4client.toString()));
}else if(frame instanceof BinaryWebSocketFrame){
BinaryWebSocketFrame binaryFrame=(BinaryWebSocketFrame)frame;
File file = new File(SERVER_SAVE_PATH+fileInfo.getString("name"));
long fileSize=fileInfo.getLong("size");
if(stopByte>=fileSize){
stopByte=fileSize;
}
JSONObject message4client=new JSONObject();
if(startByte>=fileInfo.getLong("size")){
message4client.put("startByte", 0);
message4client.put("stopByte", 0);
message4client.put("complete", true);
ctx.channel().write(new TextWebSocketFrame(message4client.toString()));
}
FileChannel fileChannel=new RandomAccessFile(file, "rw").getChannel();
fileChannel.position(fileChannel.size());
if(stopByte<fileSize){
ByteBuffer byteBuffer=ByteBuffer.allocate(BYTE_BUFFER_SIZE);
byteBuffer.clear();
byteBuffer.put(binaryFrame.getBinaryData().array());
byteBuffer.flip();
fileChannel.write(byteBuffer);
fileChannel.close();
startByte=stopByte;
stopByte=startByte+BLOCK_SIZE;
message4client.put("startByte", startByte);
message4client.put("stopByte", stopByte);
message4client.put("complete", false);
ctx.channel().write(new TextWebSocketFrame(message4client.toString()));
}else {
ByteBuffer byteBuffer=ByteBuffer.allocate(binaryFrame.getBinaryData().capacity());
byteBuffer.clear();
byteBuffer.put(binaryFrame.getBinaryData().array());
byteBuffer.flip();
fileChannel.write(byteBuffer);
fileChannel.close();
message4client.put("startByte", 0);
message4client.put("stopByte", 0);
message4client.put("complete", true);
ctx.channel().write(new TextWebSocketFrame(message4client.toString()));
}
}
}
private static void sendHttpResponse(ChannelHandlerContext ctx, HttpRequest req, HttpResponse res) {
// Generate an error page if response status code is not OK (200).
if (res.getStatus().getCode() != 200) {
res.setContent(Unpooled.copiedBuffer(res.getStatus().toString(), CharsetUtil.UTF_8));
setContentLength(res, res.getContent().readableBytes());
}
// Send the response and close the connection if necessary.
ChannelFuture f = ctx.channel().write(res);
if (!isKeepAlive(req) || res.getStatus().getCode() != 200) {
f.addListener(ChannelFutureListener.CLOSE);
}
}
private static void sendError(ChannelHandlerContext ctx, HttpResponseStatus status) {
HttpResponse response = new DefaultHttpResponse(HTTP_1_1, status);
response.setHeader(CONTENT_TYPE, "text/plain; charset=UTF-8");
response.setContent(Unpooled.copiedBuffer(
"Failure: " + status.toString() + "\r\n",
CharsetUtil.UTF_8));
ctx.write(response).addListener(ChannelFutureListener.CLOSE);
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
private static String getWebSocketLocation(HttpRequest req) {
return "ws://" + req.getHeader(HttpHeaders.Names.HOST) + WEBSOCKET_PATH;
}
}
WebServerSocket.java
/*
* Copyright 2012 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package com.wudasong.breakPoinUploadServer;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.socket.nio.NioEventLoop;
import io.netty.channel.socket.nio.NioServerSocketChannel;
/**
* A HTTP server which serves Web Socket requests at:
*
* http://localhost:8080/websocket
*
* Open your browser at http://localhost:8080/, then the demo page will be loaded and a Web Socket connection will be
* made automatically.
*
* This server illustrates support for the different web socket specification versions and will work with:
*
* <ul>
* <li>Safari 5+ (draft-ietf-hybi-thewebsocketprotocol-00)
* <li>Chrome 6-13 (draft-ietf-hybi-thewebsocketprotocol-00)
* <li>Chrome 14+ (draft-ietf-hybi-thewebsocketprotocol-10)
* <li>Chrome 16+ (RFC 6455 aka draft-ietf-hybi-thewebsocketprotocol-17)
* <li>Firefox 7+ (draft-ietf-hybi-thewebsocketprotocol-10)
* <li>Firefox 11+ (RFC 6455 aka draft-ietf-hybi-thewebsocketprotocol-17)
* </ul>
*/
public class WebSocketServer {
private final int port;
public WebSocketServer(int port) {
this.port = port;
}
public void run() throws Exception {
ServerBootstrap b = new ServerBootstrap();
try {
b.eventLoop(new NioEventLoop(), new NioEventLoop())
.channel(new NioServerSocketChannel())
.localAddress(port)
.childHandler(new WebSocketServerInitializer());
Channel ch = b.bind().sync().channel();
System.out.println("Web socket server started at port " + port + '.');
System.out.println("Open your browser and navigate to http://localhost:" + port + '/');
ch.closeFuture().sync();
} finally {
b.shutdown();
}
}
public static void main(String[] args) throws Exception {
int port;
if (args.length > 0) {
port = Integer.parseInt(args[0]);
} else {
port = 8082;
}
new WebSocketServer(port).run();
}
}
客户端代码:
MyHtml.html
<!DOCTYPE html>
<html>
<head>
<title>MyHtml.html</title>
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="this is my page">
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
</head>
<body>
<input type="file" id="files" name="file" />
<input type="button" id="upload" value="上传" />
<input type="button" id="stop" value="暂停" />
<script type="text/javascript" src="upload.js"></script>
</body>
</html>
upload.js
var socket;
//openSocket("ws://localhost:8082/websocket");
document.getElementById("stop").addEventListener("click", function(){
socket.close();
}, false);
document.getElementById("upload").addEventListener("click", function(){
openSocket("ws://localhost:8082/websocket");
setTimeout(function(){
fileUpload();
}, 500);
}, false);
function openSocket(url){
if(!window.WebSocket){
window.WebSocket=window.MozWebSocket;
}
if(window.WebSocket){
socket=new WebSocket(url);
// socket=new WebSocket("ws://localhost:8082/websocket");
socket.onopen=onOpen;
socket.onclose=onClose;
}else {
alert("your browser does not support websocket");
}
};
function onOpen(event){
console.log("websocket is opened");
}
function onClose(event){
console.log("websocket is closed");
}
function fileUpload(){
var files = document.getElementById('files').files;
if (!files.length) {
alert('Please select a file!');
return;
}
var file = files[0];
var fileInfo={
"opcode":1,
"name":file.name,
"size":file.size,
"lastModifiedDate":file.lastModifiedDate
};
// console.log(JSON.stringify(fileInfo));
send(JSON.stringify(fileInfo));
socket.onmessage=function(event){
var startStop=JSON.parse(event.data);
if(startStop.startByte===startStop.stopByte||startStop.complete){
console.log(startStop);
alert("文件上传成功!");
}else {
console.log(startStop);
readBlob(files,startStop.startByte, startStop.stopByte);
}
};
}
function send(message){
if(!window.WebSocket){
return;
}
if(socket.readyState==WebSocket.OPEN){
socket.send(message);
}else{
console.log("the socket is not open");
}
}
function readBlob(files,opt_startByte, opt_stopByte) {
if (!files.length) {
alert('Please select a file!');
return;
}
var file = files[0];
var start = parseInt(opt_startByte) || 0;
var stop = parseInt(opt_stopByte) || file.size - 1;
var reader = new FileReader();
if (file.webkitSlice) {
var blob = file.webkitSlice(start, stop);
} else if (file.mozSlice) {
var blob = file.mozSlice(start, stop);
}
reader.readAsArrayBuffer(blob);
reader.onloadend = function(evt) {
if (evt.target.readyState == FileReader.DONE) { // DONE == 2
send(reader.result);
}
};
}
搞定..
求多多指教!!