- 浏览: 5981 次
- 性别:
- 来自: 广州
最近访客 更多访客>>
文章分类
最新评论
-
classicbride:
能不能分享一下源码呀..我也在项目中遇到这个问题..超大文件上 ...
WEB多线程Socket文件上传 -
youbin_:
重新——呵呵
web应用程序客户端离线判断功能 -
youbin_:
看来我要重新学习语文了…
简单点,就是MSN的离开功能。MSN ...
web应用程序客户端离线判断功能 -
icefire:
呵呵!
你在编辑窗口定时用ajax发送个消息就行啦!
也可以顺 ...
web应用程序客户端离线判断功能 -
youbin_:
当然我是指客户端即浏览器!
web应用程序客户端离线判断功能
郁闷,第一次发个帖就被扣10分,呜呜……
不过我脸皮厚,又来了。
这次的问题是我在WEB应用中要实现“大”(几百兆)文件的上传,如果用IE上传,肯定Over!我用有证书的Applet在客户端用多线程通过socket将文件上传。在本机上测试好像可以,但是通过网络上传时就会发生掉包现象,必须重新上传。虽然这是程序自动的,但这样也会浪费大量的时间,有时会重复好几次。我检查了好几次代码,也没有发现什么问题!不知道是不是socket的传输不可靠呢,还是我的代码本身就有问题呢?下面是我的试验代码中主要的2个类,请大家帮我看看是否有什么地方不妥的,谢谢!!
第一个:文件上传处理程序,处理文件上传逻辑
package test;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.RandomAccessFile;
import java.net.Socket;
import java.net.UnknownHostException;
import javax.swing.JOptionPane;
import javax.swing.JProgressBar;
import javax.swing.SwingUtilities;
/**
* $Id: UploadHandler.java,v 1.1 2007/05/14 06:11:02 zhangyb Exp $
*
* 描述: 文件上传处理程序,处理文件上传逻辑
*
*
* @author zhangyb
* @version 1.0
*/
public class UploadHandler extends Thread {
/** 系统日志 */
// private final Log logger = LogFactory.getLog(UploadHandler.class);
/** 最大文件块大小 20M */
public final static long MAX_FILE_BLOCK_SIZE = 10 * 1024 * 1024;
/** 最大缓存大小 1M */
public final static int MAX_BUFFER_SIZE = 1024 * 1024;
/** 文件上传的最大线程数 */
public final static int MAX_THREADS = 5;
/** 文件系统中的文件 */
private java.io.File realFile;
/** 文件的块数 */
private int blocks;
/** 当前上传的块序号 */
private int currentBlock = 1;
/** 最后块的大小 */
private long lastLength;
/** 正在上传的线程数 */
private int threads = 0;
/** 文件的唯一编号 */
private String fileCode = "aaaaaaaaaaaaaaaaaaaa";
/** 远程主机 */
private String host;
/** 远程主机监听端口 */
private int port;
private JProgressBar progressBar = null;
private ProgressDialog dialog = null;
private FileUpload applet = null;
/**
* When the worker needs to update the GUI we do so by queuing a Runnable for the event dispatching thread with SwingUtilities.invokeLater(). In this case we're just changing the progress bars value.
*/
public void updateStatus(final int i) {
Runnable doSetProgressBarValue = new Runnable() {
public void run() {
progressBar.setValue(i);
}
};
SwingUtilities.invokeLater(doSetProgressBarValue);
}
public UploadHandler(String host, int port, java.io.File file) {
// logger.info("开始上传文件" + file.getName() + "...");
this.host = host;
this.port = port;
this.realFile = file;
start();
}
public UploadHandler(String host, int port, java.io.File file, ProgressDialog dialog, FileUpload applet) {
// logger.info("开始上传文件" + file.getName() + "...");
this.host = host;
this.port = port;
this.realFile = file;
this.dialog = dialog;
this.progressBar = dialog.getProgressBar();
this.applet = applet;
start();
}
public void run() {
if (realFile.isDirectory()) {
// 文件夹情况
java.io.File[] files = realFile.listFiles();
if (files != null || files.length > 0) {
for (int i = 0; i < files.length; i++) {
new UploadHandler(host, port, files[i]);
}
}
} else {
// 文件情况, 上传文件
try {
RandomAccessFile randomAccessFile = new RandomAccessFile(realFile, "r");
long size = randomAccessFile.length();
randomAccessFile.close();
lastLength = size % MAX_FILE_BLOCK_SIZE;
if (lastLength == 0) {
blocks = (int) (size / MAX_FILE_BLOCK_SIZE);
} else {
blocks = (int) (size / MAX_FILE_BLOCK_SIZE) + 1;
}
// progressBar.setMaximum((int) size);
progressBar.setValue(0);
progressBar.setStringPainted(true);
if (blocks >= MAX_THREADS) {
threads = MAX_THREADS;
} else {
threads = blocks;
}
for (int i = 0; i < threads; i++) {
new BlockSender(currentBlock);
currentBlock += 1;
}
} catch (FileNotFoundException e) {
// logger.error("文件" + file.getFileCode() + "未能找到, 不能完成上传.");
reset();
} catch (IOException e) {
// logger.error("发生文件或网络读写错误, 不能完成上传.");
reset();
}
}
}
/**
* 文件块上传类
*/
class BlockSender extends Thread {
int block;
Socket socket;
BlockSender(int block) {
this.block = block;
try {
// socket = new Socket(host, port);
socket = new Socket("localhost", 5000);
start();
} catch (UnknownHostException e) {
e.printStackTrace();
System.out.println("未能找到远程主机, 不能完成上传.");
reset();
} catch (IOException e) {
e.printStackTrace();
System.out.println("建立网络连接失败, 不能完成上传.");
JOptionPane.showMessageDialog(null, "建立网络连接失败, 不能完成上传.", "系统提示", JOptionPane.ERROR_MESSAGE);
dialog.setVisible(false);
reset();
}
}
public void run() {
try {
boolean resend = false;
BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
PrintWriter writer = new PrintWriter(socket.getOutputStream(), true);
writer.println(101);
String returnValue = reader.readLine();
if (returnValue != null && returnValue.equals(String.valueOf(201))) {
// 验证用户登录
writer.println("userName,password");
returnValue = reader.readLine();
if (returnValue != null && returnValue.equals(String.valueOf(201))) {
} else {
System.out.println("用户验证未通过.");
return;
}
// 文件名称
writer.println(fileCode + "," + realFile.getName());
// 文件块信息
writer.println(block);
OutputStream out = new DataOutputStream(new BufferedOutputStream(socket.getOutputStream()));
RandomAccessFile srcFile = new RandomAccessFile(realFile, "r");
byte[] buf = new byte[MAX_BUFFER_SIZE];
long start = (block - 1) * MAX_FILE_BLOCK_SIZE;
srcFile.seek(start);
int times = 0;
long total = getBlockSize(block);
long read = 0;
if (total % MAX_BUFFER_SIZE == 0) {
times = (int) total / MAX_BUFFER_SIZE;
} else {
times = (int) total / MAX_BUFFER_SIZE + 1;
}
int i = 0;
int length = -1;
while ((length = srcFile.read(buf)) != -1 && i < times) {
out.write(buf, 0, length);
out.flush();
i++;
read += length;
}
socket.shutdownOutput();
DataInputStream in = new DataInputStream(new BufferedInputStream(socket.getInputStream()));
long receive = in.readLong();
if (read != receive) {
System.out.println("文件" + realFile.getName() + "第" + block + "块在上传过程中掉包(" + (read - receive) + "字节), 需重传.");
resend = true;
}
reader.close();
writer.close();
srcFile.close();
srcFile = null;
out.close();
socket.close();
} else {
// System.out.println("服务器未准备好.");
System.out.print("服务器未准备好.");
return;
}
if (resend) {
new BlockSender(block);
} else {
synchronized (progressBar) {
progressBar.setValue((progressBar.getValue() + (int) getBlockSize(block)));
}
if (blocks >= currentBlock) {
new BlockSender(currentBlock);
currentBlock += 1;
} else {
threads -= 1;
if (threads == 0) {
applet.finished();
// Fix Me 这里建立备份文件夹的路径有问题?
// java.io.File backupFolder = new java.io.File(realFile.getParentFile().getAbsolutePath() + java.io.File.separator + CommonUtils.formatDate(new Date(), "yyyyMMdd"));
// if (logger.isDebugEnabled()) {
// logger.debug("备份文件夹:" + backupFolder);
// }
// if (!backupFolder.exists()) {
// backupFolder.mkdirs();
// }
//
}
}
}
} catch (FileNotFoundException e) {
// System.out.println("文件" + file.getFileCode() + "未能找到, 不能完成上传.");
e.printStackTrace();
reset();
} catch (IOException e) {
// System.out.println("发生文件或网络读写错误, 不能完成上传.");
e.printStackTrace();
reset();
}
}
}
private long getBlockSize(int block) {
if (block == blocks && lastLength > 0) {
return lastLength;
}
return MAX_FILE_BLOCK_SIZE;
}
/**
* 恢复文件的状态
*/
private void reset() {
}
}
第二个:请求处理类, 处理文件上传和任务发送等业务
package test;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.PrintWriter;
import java.io.RandomAccessFile;
import java.net.Socket;
//import org.apache.commons.logging.Log;
//import org.apache.commons.logging.LogFactory;
//import com.excellence.exchange.domain.File;
//import com.excellence.exchange.domain.Missive;
//import com.excellence.exchange.domain.Organ;
//import com.excellence.exchange.domain.TransferTask;
//import com.excellence.exchange.facade.ExchangeFacade;
//import com.excellence.exchange.util.ConfigUtils;
//import com.excellence.exchange.util.ContextUtils;
/**
* $Id: RequestHandler.java,v 1.1 2007/05/14 06:11:02 zhangyb Exp $
*
* 描述: 请求处理类, 处理文件上传和任务发送等业务
*
* @author zhangyb
* @version 1.0
*/
public class RequestHandler extends Thread {
/** 文件交换命令--上传文件 */
public static final int CMD_UPLOAD = 101;
/** 文件交换命令--创建文件夹 */
public static final int CMD_MAKE_DIR = 102;
/** 文件交换命令--发送任务 */
public static final int CMD_SEND_TASK = 103;
/** 文件交换命令--机构同步 */
public static final int CMD_SYNCHRONIZE_ORGAN = 104;
/** 文件交换命令--机构注册 */
public static final int CMD_REGISTER_ORGAN = 105;
/** 请求返回状态值--就绪 */
public static final int STATE_READY = 201;
/** 请求返回状态值--错误 */
public static final int STATE_ERROR = 202;
/** 请求返回状态值--拒绝 */
public static final int STATE_REJECT = 203;
/** 请求返回状态值--完成 */
public static final int STATE_FINISHED = 204;
// private final Log logger = LogFactory.getLog(RequestHandler.class);
private Socket request;
public RequestHandler() {
}
public RequestHandler(Socket socket) {
this.request = socket;
start();
}
public void run() {
BufferedReader reader = null;
PrintWriter writer = null;
DataOutputStream out = null;
DataInputStream in = null;
ObjectInputStream ois = null;
ObjectOutputStream oos = null;
try {
reader = new BufferedReader(new InputStreamReader(request.getInputStream()));
writer = new PrintWriter(request.getOutputStream(), true);
String command = reader.readLine();
// 请求类型信息
// if (logger.isDebugEnabled()) {
System.out.println("请求类型代码:" + command);
// }
// 返回准备好响应
writer.println(STATE_READY);
writer.flush();
// 接收用户信息(用户名,密码)
String userInfo = reader.readLine();
if (userInfo != null && !userInfo.equals("")) {
// Fix me 如果要验证用户需实现下面方法
String[] infos = userInfo.split(",");
if (!login(infos[0], infos[1])) {
System.out.println("无效的用户信息.");
writer.println(STATE_REJECT);
writer.flush();
return;
}
} else {
System.out.println("无效的用户信息.");
writer.println(STATE_ERROR);
writer.flush();
return;
}
// 返回准备好响应
writer.println(STATE_READY);
writer.flush();
// 接收文件名称(新文件名称,原始文件名称)
String line = reader.readLine();
String newName = "";
if (line != null && !line.equals("")) {
String[] names = line.split(",");
newName = names[1];
} else {
System.out.println("无效的文件名称信息.");
return;
}
// 接收文件块信息
int block = 1;
line = reader.readLine();
if (line != null && !line.equals("")) {
block = Integer.parseInt(line);
} else {
System.out.println("无效的文件块信息.");
return;
}
in = new DataInputStream(new BufferedInputStream(request.getInputStream()));
String root = "C:/";// "/tmp/youbin/";//ConfigUtils.getTargetFolder();
// 如果是有父文件夹的情况需要重新处理???
long receive = saveFile(new DataInputStream(new BufferedInputStream(request.getInputStream())), root + newName, block);
out = new DataOutputStream(new BufferedOutputStream(request.getOutputStream()));
out.writeLong(receive);
out.flush();
} catch (IOException e) {
System.out.println("发生网络读写错误, 不能正常完成请求.");
try {
out.writeInt(RequestHandler.STATE_ERROR);
out.flush();
} catch (IOException e1) {
System.out.println("网络读写错误, 未能返回错误到客户端.");
}
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
System.out.println("非正常退出请求处理.");
}
}
if (writer != null) {
writer.close();
}
if (out != null) {
try {
out.close();
} catch (IOException e) {
System.out.println("非正常退出请求处理.");
}
}
if (in != null) {
try {
in.close();
} catch (IOException e) {
System.out.println("非正常退出请求处理.");
}
}
if (ois != null) {
try {
ois.close();
} catch (IOException e) {
System.out.println("非正常退出请求处理.");
}
}
if (oos != null) {
try {
oos.close();
} catch (IOException e) {
System.out.println("非正常退出请求处理.");
}
}
if (request != null) {
try {
request.close();
} catch (IOException e) {
System.out.println("非正常退出请求处理.");
}
}
}
}
/**
* 保存文件到指定的文件夹中
*
* @param in 包含文件数据的流
* @param fileName 在文件夹中的文件名称
* @param block 当前文件块的序号
* @return 返回实际收到的长度返回给客户端验证完整性
*/
private long saveFile(InputStream in, String fileName, int block) {
long receive = 0;
try {
RandomAccessFile targetFile = new RandomAccessFile(fileName, "rws");
targetFile.seek((block - 1) * UploadHandler.MAX_FILE_BLOCK_SIZE);
byte[] buf = new byte[UploadHandler.MAX_BUFFER_SIZE];
int length = 0;
while ((length = in.read(buf)) != -1) {
targetFile.write(buf, 0, length);
receive += length;
}
targetFile.close();
targetFile = null;
} catch (FileNotFoundException e) {
e.printStackTrace();
// 这里不应该出现异常.
} catch (IOException e) {
// Fix Me 这里需要处理
e.printStackTrace();
}
return receive;
}
/**
* 验证用户有效性
*
* TODO 如果需要验证则实现下面方法
*
* @param userName
* @param password
* @return
*/
private boolean login(String userName, String password) {
return true;
}
}
相关推荐
第七章 案例1通过委托实现异步调用 案例2使用定时器执行方法 案例3...多线程TCP服务端实现 案例6用Socket连接获取客户端地址 案例8如何实现UDP通讯协议 案例9如何使用STMP协议发送电子邮件 第九章...
※用多线程的方式并发连接登录多台LINUX服务器,实现并发命令操作、文件分发,实时结果返回,并可根据服务器性能控制线程量,千台机器改密码1分钟完成。 3、HTML/JAVAScript基础 4、WEB JS Package BootStrap 介绍...
熟练掌握java基础,包括面向对象、多线程、IO流、UDP/TCP、socket、文件上传下载、XML解析、JSON解析、servlet、filter、listener、HTTP协议等等; 熟练掌握 使用jdbc标准连接数据库,掌握DDL、DML、DCL、DQL和...
28_网络通信之通过HTTP协议实现文件上传.avi 所在项目:newsmanage & Web端应用:web 29_发送xml数据和调用webservice.avi 所在项目:mobileAddressQuery & Web端应用:web 30_多线程下载原理.avi 所在项目:net 31_...
28_网络通信之通过HTTP协议实现文件上传.avi 所在项目:newsmanage & Web端应用:web 29_发送xml数据和调用webservice.avi 所在项目:mobileAddressQuery & Web端应用:web 30_多线程下载原理.avi 所在项目:net 31_...
28_网络通信之通过HTTP协议实现文件上传.avi 所在项目:newsmanage & Web端应用:web 29_发送xml数据和调用webservice.avi 所在项目:mobileAddressQuery & Web端应用:web 30_多线程下载原理.avi 所在项目:net 31_...
Java局域网通信——飞鸽传书源代码,大家都知道VB版、VC版还有Delphi版的飞鸽传书软件,但是Java版的确实不多,因此这个Java文件传输实例不可错过,Java网络编程技能的提升很有帮助。 Java聊天程序,包括服务端和...
一个支持多线程的服务器框架,GeneralServer.java; 代理服务器,ProxyServer.java; telnet客户端,访问系统的telnet服务实质上是与telnet服务建立socket连接,默认的telnet服务的端口是23,TelnetClient.java; ...
实例133 碰撞的球(多线程) 382 实例134 钟表(多线程) 387 实例135 模拟生产者与消费者 392 实例136 仿迅雷下载文件 396 第15章 图形编程 403 实例137 多变的按钮 403 实例138 自制对话框 405 实例139 ...
Django获取多个数据以及文件上传 Django的CBV和FBV Django模板语言循环字典 Django基于正则表达式的URL Django对应的路由名称 Django路由分发 DjangoORM基本创建基本类型以及生成数据库结构 DjangoORM使用mysql注意 ...
4. 文件上传、多线程下载服务化、发送邮件、短信服务化、部门信息服务化、产品信息服务化、信息发布服务化、我的订阅服务化、我的任务服务化、公共链接、我的收藏服务化等 系统模块: 1. 用户管理: 用户信息...
Java局域网通信——飞鸽传书源代码,大家都知道VB版、VC版还有Delphi版的飞鸽传书软件,但是Java版的确实不多,因此这个Java文件传输实例不可错过,Java网络编程技能的提升很有帮助。 Java聊天程序,包括服务端和...
Java局域网通信——飞鸽传书源代码,大家都知道VB版、VC版还有Delphi版的飞鸽传书软件,但是Java版的确实不多,因此这个Java文件传输实例不可错过,Java网络编程技能的提升很有帮助。 Java聊天程序,包括服务端和...
Java局域网通信——飞鸽传书源代码,大家都知道VB版、VC版还有Delphi版的飞鸽传书软件,但是Java版的确实不多,因此这个Java文件传输实例不可错过,Java网络编程技能的提升很有帮助。 Java聊天程序,包括服务端和...
Java局域网通信——飞鸽传书源代码,大家都知道VB版、VC版还有Delphi版的飞鸽传书软件,但是Java版的确实不多,因此这个Java文件传输实例不可错过,Java网络编程技能的提升很有帮助。 Java聊天程序,包括服务端和...
Java局域网通信——飞鸽传书源代码,大家都知道VB版、VC版还有Delphi版的飞鸽传书软件,但是Java版的确实不多,因此这个Java文件传输实例不可错过,Java网络编程技能的提升很有帮助。 Java聊天程序,包括服务端和...
01 selctors实现文件上传与下载 02 html的介绍 03 html文档树的概念 04 meta标签以及一些基本标签 05 img标签和列表标签 06 form表单之input标签 07 通过form向server端发送数据 08 form表单之select标签 09 table...