我的迅雷程序加速问题(code2)

py330316117 2009-11-07 10:23:48
 class DownLoadFile extends Thread
{
private JPanel progressPane;
private String URL;//url地址
private String saveURL;//保存地址
int nthread;//线程数
String info = new String();//字符串info
JTextArea textArea = new JTextArea();//文本区对象
JProgressBar jProgressBar;//进度条
long[] startPos;//开始字节数
long[] endPos;//结束字节数
long fileLength;//文件长度
DownLoadFileThread[] downFileSplitter;//文件下载线程数组
Timer timer;

//构造方法
public DownLoadFile(String URL, String saveURL, JTextArea textArea,
int nthread, JProgressBar jProgressBar)
{
this.jProgressBar = jProgressBar;
this.URL = URL;
this.saveURL = saveURL;
this.nthread = nthread;
this.startPos = new long[nthread];
this.endPos = new long[nthread];
this.textArea = textArea;
}
//重写run方法
public void run()
{
info = "目标文件: " + URL;
textArea.append("\n" + info);//输出目标文件地址
info = "\n 线程总数: " + nthread;
textArea.append("\n" + info);//输出线程总数
try
{
fileLength = getFileSize(URL);//获得文件长度大小
if (fileLength == -1)
{//如果无法得到文件长度,输出提示
textArea.append("\n 不可知的文件长度!请重试!!");
} else
{
if (fileLength == -2)
{//如果无法获取文件,输出提示,检查路径
textArea.append("\n 文件无法获取!请重试或检查路径!!");
} else
{//根据文件长度,确定每个线程的开始字节数和结束字节数,输出线程和下载范围
for(int i = 0; i < startPos.length; i++)
startPos[i] = (long) (i * (fileLength / startPos.length));
for (int i = 0; i < endPos.length - 1; i++)
endPos[i] = startPos[i + 1];
endPos[endPos.length - 1] = fileLength;
for (int i = 0; i < startPos.length; i++)
{
info = "线程:" + i + "下载范围:" + startPos[i] + "--"+ endPos[i];
textArea.append("\n" + info);
}
//创建文件下载线程数组对象,设置进度条
downFileSplitter = new DownLoadFileThread[startPos.length];
jProgressBar.setMaximum(100);
jProgressBar.setMinimum(0);
jProgressBar.setStringPainted(true);
jProgressBar.setString("0%");
for (int i = 0; i < startPos.length; i++)
{//创建文件下载线程对象,启动线程并输出信息
downFileSplitter[i] = new DownLoadFileThread(URL,startPos[i], endPos[i], i, textArea,jProgressBar, saveURL);
info = "线程 " + i + "启动";
textArea.append("\n" + info);
downFileSplitter[i].start();
}
//进度条设置,重写actionPerformed方法,进度条随下载进度变化
timer = new Timer(100, new ActionListener()
{
public void actionPerformed(ActionEvent arg0)
{
int readTotal = 0;
boolean finished = true;
for (int i = 0; i < startPos.length; i++)
{
if (downFileSplitter[i].isAlive())
finished = false;
readTotal += downFileSplitter[i].getReadPos();
}
jProgressBar.setValue((int) ((long) (readTotal) * 100f / fileLength));
jProgressBar.setString((int) ((long) (readTotal) * 100f / fileLength)+ "%");
if (finished)
{
if ((long) readTotal == fileLength)
JOptionPane.showMessageDialog(null,"下载完成!!!");
else
JOptionPane.showMessageDialog(null,"未能完成下载!!!");
timer.stop();
}
}
});
timer.start();
}
}
} catch (Exception e)
{
e.printStackTrace();
}
}

//获取文件大小的方法,返回文件长度
public long getFileSize(String URL)
{
int fileLength = -1;
try
{//连接网络,获取响应
URL url = new URL(URL);
HttpURLConnection httpConnection = (HttpURLConnection) (url.openConnection());
int responseCode = httpConnection.getResponseCode();
if (responseCode >= 400)
{
System.out.println("Web服务器响应错误");
return -2;// Web服务器响应错误
}
String sHeader;//文件长度的文件头
for (int i = 1;; i++)// 查找标识文件长度的文件头,获取文件长度
{
sHeader = httpConnection.getHeaderFieldKey(i);
if (sHeader != null)
{
if (sHeader.equals("Content-Length"))
{//显示文件的长度
int length=httpConnection.getContentLength();
textArea.append("\n 文件长度:---"+length);
fileLength = Integer.parseInt(httpConnection.getHeaderField(sHeader));
textArea.append("\n 可知的文件长度:"+fileLength);
break;
}
} else
{
break;
}
}
} catch(Exception e)
{
e.printStackTrace();
}
return fileLength;
}
}
//定义DownLoadFileThread类,继承Thread类
class DownLoadFileThread extends Thread
{
private JProgressBar jProgressBar;//进度条
String URL;//url地址
long startPos;//开始字节数
long endPos;//结束字节数
int threadID;//线程号
JTextArea textArea=new JTextArea();//文本区
RandomAccessFile file;//随机访问文件流
private int readPos = 0;
private int in = 0;
//构造方法
public DownLoadFileThread(String URL,long startPos,long endPos,int id,JTextArea textArea
,JProgressBar jProgressBar,String saveURL)throws IOException
{
this.jProgressBar = jProgressBar;
this.URL = URL;
this.startPos = startPos;
this.endPos = endPos;
this.threadID = id;
this.textArea = textArea;
file=new RandomAccessFile(saveURL,"rw");//创建名为saveURL,权限为读写的文件
file.seek(startPos);//从startPos字节数的下一位置进行读写操作
}
//重写run方法
public void run()
{
try
{//连接地址,创建连接
URL url = new URL(URL);
HttpURLConnection httpConnection=(HttpURLConnection)url.openConnection();
String sProperty="bytes="+startPos+"-";
httpConnection.setRequestProperty("RANGE",sProperty);//设置请求属性
textArea.append("\n 线程"+threadID+"下载文件……请等待");
InputStream input=httpConnection.getInputStream();//得到输入流
byte[] buf=new byte[10000000];
int offset;
offset=(int)endPos-(int)startPos;//每个线程读取的字节数
if(offset>10000000)
offset=10000000;
while((in = input.read(buf,0,offset))>0 && startPos<endPos)
{//显示各个线程读取的字节数以及起始字节数和结束字节数,直到下载完成
if(((int) endPos - (int) startPos)<1024)
in = (int) endPos - (int) startPos;
readPos +=in;
textArea.append("\n 线程"+threadID+" 已读取"+readPos+"个字节, start is :"+startPos+" and end is:"+endPos+"。");
offset = (int) endPos - (int) startPos;
if (offset > 10000000)
offset = 10000000;
file.write(buf,0,in);//写入文件
startPos+=in;
}
textArea.append("\n 线程"+threadID+"下载完毕!!");
file.close();
input.close();
}catch(Exception ex)
{
ex.printStackTrace();
}
}
public int getReadPos()
{
return readPos;
}
public void setReadPos(int readPos)
{
this.readPos = readPos;
}
}
//定义代理类,继承JFrame类实现ActionListener接口
class ProxyPanel extends JFrame implements ActionListener
{
private String host = "000.000.000.000";//设置主机默认地址
private String port = "0000";//设置主机默认端口
private JLabel label1 = new JLabel("主机:");//标签提示
private JLabel label2 = new JLabel("端口:");//标签提示
private JTextField hosttext = new JTextField();//主机文本框
private JTextField porttext = new JTextField();//端口文本框
private JButton button = new JButton("确定");//确定按钮

//构造方法
public ProxyPanel(int x, int y)
{
//创建面板、设置面板布局,添加标签、文本框到面板中,设置位置、大小
JPanel panel = new JPanel();
panel.setLayout(null);
label1.setBounds(20, 20, 40, 20);
hosttext.setBounds(60, 20, 140, 20);
panel.add(label1, null);
panel.add(hosttext, null);
hosttext.setText(host);
label2.setBounds(20, 60, 40, 20);
porttext.setBounds(60, 60, 140, 20);
panel.add(label2);
panel.add(porttext);
porttext.setText(port);
button.setBounds(85, 100, 60, 20);//设置按钮位置、大小
button.addActionListener(this);//给按钮添加监听器
panel.add(button);//添加按钮到面板中
getContentPane().add(panel);//添加面板到内容窗
setSize(new Dimension(240, 160));//设置大小
setVisible(true);//设置可见性
setLocation(x, y);//设置位置
}
public String getHost()
{
return this.host;
}
public String getPort()
{
return this.port;
}
//重写actionPerformed方法,获取系统属性
public void actionPerformed(ActionEvent arg0)
{
if (arg0.getSource() == button)
{
host = hosttext.getText();
port = porttext.getText();
System.getProperties().put("proxySet", "true");
System.getProperties().put("proxyHost", host);
System.getProperties().put("proxyPort", port);
this.setVisible(false);
}
}
}


和“我的迅雷程序代码(code1)”和在一起就是我的迅雷程序,但是运行起来太慢了(试过了下载的文件能使用),下载几百kb的视频要好几小时(没有耐性的人是等不了啊)
希望大家能给看看,集思广益,我没有给分是因为怕有些人看不完这么长的代码,那问题永远解决不了。如果能解决了我给300(恐怕我也就这么多分)
...全文
690 28 打赏 收藏 举报
写回复
用AI写文章
28 条回复
切换为时间正序
请发表友善的回复…
发表回复
爱摸鱼de老邪 2009-11-14
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 py330316117 的回复:]
迅雷基本传输文件就是这么简单,其他功能只是后加上去的,只不过我这个传输文件时用byte传输文件,有最大的限制,不知道什么类型的传输文件能没有最大限制。我编的程序绝对好使,我传过文件了,不要以为迅雷是多么牛x的东西
[/Quote]
借用楼主的话,一般网络文件传输工具的基本功能都是这么简单,信息网络传输的基本形式就是比特流,一个几百K的视频要好几个小时,这就是差距,况且迅雷的核心技术根本不在楼主说的这块。如果楼主如此有信心,给时间就能超过迅雷,那你何不集中时间搞个产品超过迅雷呢,迅雷已经在赚钱了,楼主搞一个超过它,我想你为此辞职付出的时间、金钱都能得到回报,何乐而不为呢。
py330316117 2009-11-14
  • 打赏
  • 举报
回复
那我辞职这段时间吃什么,喝什么,你养我啊
liang8305 2009-11-13
  • 打赏
  • 举报
回复
你弄明白了迅雷到底牛在哪里吗?仅仅是一个多线程下载,就说迅雷不是什么牛东西?
sxjkk 2009-11-13
  • 打赏
  • 举报
回复
一般的下载速度取决与网络带宽

建议楼主用JAVA自带的缓冲流:BufferedInputStream,来读取数据

你自定义的缓冲太大了,应该定义为1024的长度就完全够用,每读满一个缓冲就在本地写一次文件

我做的一个项目,自己写了一个多线程的HTTP下载,就是这么做的,局域网的速度都在10m左右,外网在40多K,这个取决连接的带宽和网站能提供的下载速度
dm520 2009-11-13
  • 打赏
  • 举报
回复
[Quote=引用 23 楼 zhc8501 的回复:]
本领没有那么高下来研究一下,很赞赏你的学习精神,学习就应该敢于质疑权威
[/Quote]
说的好
zhc8501 2009-11-13
  • 打赏
  • 举报
回复
本领没有那么高下来研究一下,很赞赏你的学习精神,学习就应该敢于质疑权威
啤酒泡泡 2009-11-12
  • 打赏
  • 举报
回复
占位,下班回去看..
magicelfzz 2009-11-12
  • 打赏
  • 举报
回复
有意思~~~帮顶!!!!!!!!!!!!
truediego 2009-11-12
  • 打赏
  • 举报
回复
[Quote=引用 18 楼 py330316117 的回复:]
byte那个数组不输存储套接字的,是存储文件的字节的,我用那么大空间存套接字干嘛?
[/Quote]

我怎么看着是用来读socket,然后用来写文件的
py330316117 2009-11-11
  • 打赏
  • 举报
回复
socket buffer
是网络套接字 ,他和流量每有关系吗?如果有关系是怎么限制流量的
py330316117 2009-11-11
  • 打赏
  • 举报
回复
byte那个数组不输存储套接字的,是存储文件的字节的,我用那么大空间存套接字干嘛?
zeroasan_ 2009-11-11
  • 打赏
  • 举报
回复
可以将下载的时间分成两个部分:
A. 网络时间,把数据传输到本地的时间。
B. 将数据写入磁盘的时间。B

现在楼主的程序里是这样的
读+写+读+写
读和写交替进行,不能并行,所以时间是 A+B

如果将缓存放大,然后两个线程
1. 从网络传输到本地内存的buffer的线程
2. 写磁盘的线程
两个线程共享buffer,这样的话时间是 max(A|B) 可以缩短时间


如果是真的要像迅雷那样的速度的话,网络资源的搜索的功能就需要加强。这可能和迅雷有一个强大的资源搜索服务器有密切的关系。
用户用迅雷下载,迅雷服务器记录用户资源,从而建立资源索引,达到资源共享。
所以下载客户端并不是高速下载最强大的部分。


truediego 2009-11-11
  • 打赏
  • 举报
回复
流量?流量是个速度的概念,限制流量就是限制速度,
加入限制每秒50kb,那读到50kb,就sleep一会儿,然后继续读,就起到限制流量的作用了

但是流量跟socket buffer没啥直接关系。

socket是网络套接字,socket buffer只是其缓存, 我说的8k是该缓存的大小
它的缓存就8k,你用1000000的内存去读8k,也顶多读出8k来,所以我觉得设100000没什么用
你把1000000的内存往文件里面写,也可能会降低速度
py330316117 2009-11-10
  • 打赏
  • 举报
回复
download那个线程的buf开的空间太大了, 10000000, 貌似socket每次最多传8×1024,所以我认为buf开到8×1024就足够了。太大了很可能会变慢
小的我试过了 也很慢
真正的迅雷下载可以达到1m 如果只是设置8*1024那么才8kb,
truediego 2009-11-10
  • 打赏
  • 举报
回复
个人觉得有下面几个问题
1. download那个线程的buf开的空间太大了, 10000000, 貌似socket每次最多传8×1024,所以我认为buf开到8×1024就足够了。太大了很可能会变慢

2.线程数也取决于你的机子的TCP/IP的最大连接数,我觉得也需要确认一下

3.download线程里,不建议去更新画面,需要更新画面的话,将值写到变量里面,另设线程去读这个变量然后更新画面好了。

不知道说的对错,不过觉得值得一试
cchaha 2009-11-10
  • 打赏
  • 举报
回复
有意思,也有兴趣,帮顶
wifewifewife 2009-11-10
  • 打赏
  • 举报
回复
.
springbird 2009-11-10
  • 打赏
  • 举报
回复
顶起来
truediego 2009-11-10
  • 打赏
  • 举报
回复
[Quote=引用 12 楼 py330316117 的回复:]
小的我试过了 也很慢
真正的迅雷下载可以达到1m  如果只是设置8*1024那么才8kb,
[/Quote]

8kb是socket buffer的大小,也就是一次接收数据的最大空间,并不是下载速度,
你说迅雷1m,应该说的是它的下载速度吧,而不是socket buffer的大小。
这个socket buffer的大小已经由你的OS决定了,你设置再大的buffer去read也是没用的。

作为一个实验,你可以把 in = input.read(buf,0,offset) 的in的值debug出来看看,
如果我说的是对的话,这个值不会超过8k的


而且,几百K的视频要好几个小时,这也太不正常了吧
就算单线程的http下载,也用不了多久的啊。
苍蝇①号 2009-11-09
  • 打赏
  • 举报
回复
我认真读了下你的代码,觉得有可行性,之前的话语不好意思啊。下面我对你这句话不是很明白。
“只不过我这个传输文件时用byte传输文件,有最大的限制,不知道什么类型的传输文件能没有最大限制.”
最大限制指的是什么?
文件除了byte传输外难道还有别的方式?
加载更多回复(7)

62,620

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧