`
aasonwu
  • 浏览: 34584 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

基于html5 websocket API简单实现断点上传文件

阅读更多

本实例只是简单地实现文件的断点上传功能,有更好的建议请不吝赐教


本实例基于html5的 websocket API和netty框架,如果您对两个技术不太熟悉,可以点击下面连接了解

websocket: http://www.chinaz.com/web/2012/0806/267188.shtml

http://www.websocket.org/

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);
		}
	};
}

搞定..

求多多指教!!

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics