- 浏览: 6051 次
- 性别:
- 来自: 广州
最近访客 更多访客>>
文章分类
最新评论
-
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;
}
}
相关推荐
### Java多线程+Socket实现的漂亮QQ #### 技术要点分析 ##### 1. Java Swing Java Swing 是一个用于构建图形用户界面 (GUI) 的轻量级组件集,它为开发人员提供了丰富的功能来设计复杂的用户界面。在本项目中,...
在这个“安卓使用socket上传文件demo”中,我们将深入探讨如何利用Socket在安卓应用中实现文件上传功能。 首先,让我们了解Socket的基本概念。Socket是网络通信的基础,它允许两个网络端点(通常是服务器和客户端)...
### socket支持断点续传Java多线程下载技术解析 #### 概述 在软件开发领域,特别是对于大型文件的下载需求,断点续传功能显得尤为重要。它能够确保在网络不稳定的情况下,用户仍然可以顺利地完成文件下载。本文将...
通过这个视频教程,开发者将能够掌握ASP.NET中多线程的应用,理解如何在IIS环境下优化Web应用,同时学习到Socket编程、模拟IIS、一般处理程序的使用,以及如何实现异步无刷新分页和有效利用服务器端控件。...
多线程是并发执行多个任务的技术,尤其在处理大文件上传下载时,多线程可以显著提高程序性能。例如,当上传一个大文件时,可以创建两个线程,一个负责读取本地文件,另一个负责发送数据到服务器。这样,读取和发送...
7. **FTP协议处理**:FTP协议有多种命令,如USER/PASS用于认证,STOR/RETR用于文件上传和下载,需要正确实现FTP命令交互。 8. **文件I/O操作**:下载的数据需要写入本地文件,涉及文件打开、读写、关闭等操作,注意...
此外,我已开发了一款下载器,它运用多线程技术来提升下载速度,支持HTTP和FTP协议,并具有文件分块传输、文件重命名、速度控制和复制URL到剪贴板等更多功能。该下载器已在Windows平台上进行了测试,运行稳定且速度...
在文件上传场景下,客户端(通常是Web应用程序)通过Socket连接到服务器,然后将文件的二进制数据流式传输到服务器端。 1. 创建Socket连接:客户端使用Socket类的构造函数指定服务器的IP地址和端口号,建立连接。 2...
多线程下载是将一个文件分成多个部分,每个部分由单独的线程进行下载。这种方式可以充分利用网络带宽,提高下载速度。在VC++6.0环境下,开发者通常会利用MFC(Microsoft Foundation Classes)库来构建Windows应用...
同时,服务端可能需要优化存储策略,例如使用多线程处理文件,或者使用流式存储来减少内存消耗。 综上所述,本案例提供的C#文件上传方案涵盖了从基础的C#编程、Socket通信到文件上传的完整流程,对于理解C#文件操作...
多线程下载是提高文件下载速度的一种技术,通过同时启动多个下载线程,可以从服务器并行获取文件的不同部分,从而加快整体下载速度。在实现中,通常需要对文件进行分割,每个线程负责下载一部分,然后在本地进行合并...
在IT行业中,文件上传下载是网络应用的基本功能之一,尤其在Web开发中至关重要。本教程主要聚焦于使用C#语言实现TCP协议下的文件上传下载功能。C#是一种面向对象的编程语言,它提供了丰富的库和工具来处理网络通信,...
在IT领域,文件上传是一项常见的功能,特别是在web应用和云服务中。文件上传允许用户将本地计算机上的数据或文件传输到服务器,以便于共享、存储或处理。本篇将深入探讨文件上传的相关知识点,包括其原理、实现方式...
本文将详细探讨如何实现“上传下载文件”功能,以及它与socket通讯和多线程技术的关系。 首先,让我们了解上传和下载的基本概念。上传是指将本地计算机上的文件发送到远程服务器的过程,而下载则是相反的操作,即从...
- **FTP服务器**:基于TCP Socket实现文件上传下载。 - **聊天室**:使用UDP Socket实现实时的消息传递。 - **Web服务器**:HTTP协议是基于TCP的,可以使用Socket实现简单的HTTP服务器。 通过学习Delphi Socket...
通过这个项目,你可以学习到Java网络编程的基本原理,了解TCP和UDP的区别,掌握多线程的应用,并熟悉文件操作。实践中遇到的问题和解决过程将加深你对这些概念的理解。如果你是初学者,这是一个很好的起点,可以帮你...
- 文件上传涉及到处理multipart/form-data格式的POST请求。 5. **POST请求的常见问题**: - "POST No Response"问题通常是由于服务器没有正确处理POST请求,或者客户端没有正确关闭Socket导致的。 - 常见解决...
8. **性能优化**:为了提高上传和下载速度,可以使用多线程或多进程,同时传输多个数据块。此外,还可以考虑使用非阻塞I/O或异步I/O来改善性能。 9. **安全性**:在实际应用中,文件上传和下载需要考虑安全性。这...
在 Delphi 中,可以使用 Indy 或其他库来创建 HTTP 客户端和服务器,处理 GET、POST 等请求,实现文件上传下载、Web服务调用等功能。 3. **epoll (Linux)**:epoll 是 Linux 系统提供的高效 I/O 事件通知机制,适用...
3. 并发控制:支持多线程或异步IO,提高文件下载速度。 4. 断点续传:记录已下载的部分,当连接中断后可以从上次的位置继续下载。 5. 安全性:可能集成SSL/TLS支持,提供安全的数据传输。 总结来说,SocketMgr_...