一个网友正好需要这个东西,我就把几个技术整合到了一起。包括三个部分,实现时也是逐个做到的
- 多线程的文件下载,HTTP协议
- 把这个功能做成一个HTTP的服务,侦听在某个端口上,方便非Java的系统使用
- 把这个功能封装为一个Windows服务,在机器启动时可以自动启动
我们逐个看程序。
一、多线程下载这个主要使用了HTTP协议里面的一个Range参数,他设置了你读取数据的其实位置和终止位置。 经常使用flashget的用户在查看连接的详细信息时,应该经常看到这个东西。比如
Range:bytes=100-2000
代表从100个字节的位置开始读取,到2000个字节的位置结束,应读取1900个字节。
程序首先拿到文件的长度,然后分配几个线程去分别读取各自的一段,使用了
RandomAccessFile
进行随机位置的读写。
下面是完整的下载的代码。
- package net.java2000.tools;
- import java.io.BufferedInputStream;
- import java.io.File;
- import java.io.IOException;
- import java.io.RandomAccessFile;
- import java.net.URL;
- import java.net.URLConnection;
- public class HTTPDownloader extends Thread {
-
- private String page;
-
- private String savePath;
-
- private int threadNumber = 2;
-
- private String referer;
-
- private int MIN_BLOCK = 10 * 1024;
- public static void main(String[] args) throws Exception {
- HTTPDownloader d = new HTTPDownloader("http://www.xxxx.net/xxxx.rar", "d://xxxx.rar", 10);
- d.down();
- }
- public void run() {
- try {
- down();
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-
- public void down() throws Exception {
- URL url = new URL(page);
- URLConnection con = url.openConnection();
- int contentLen = con.getContentLength();
- if (contentLen / MIN_BLOCK + 1 < threadNumber) {
- threadNumber = contentLen / MIN_BLOCK + 1;
- }
- if (threadNumber > 10) {
- threadNumber = 10;
- }
- int begin = 0;
- int step = contentLen / threadNumber;
- int end = 0;
- for (int i = 0; i < threadNumber; i++) {
- end += step;
- if (end > contentLen) {
- end = contentLen;
- }
- new HTTPDownloaderThread(this, i, begin, end).start();
- begin = end;
- }
- }
- public HTTPDownloader() {
- }
-
- public HTTPDownloader(String page, String savePath) {
- this(page, savePath, 10);
- }
-
- public HTTPDownloader(String page, String savePath, int threadNumber) {
- this(page, page, savePath, 10);
- }
-
- public HTTPDownloader(String page, String referer, String savePath, int threadNumber) {
- this.page = page;
- this.savePath = savePath;
- this.threadNumber = threadNumber;
- this.referer = referer;
- }
- public String getPage() {
- return page;
- }
- public void setPage(String page) {
- this.page = page;
- }
- public String getSavePath() {
- return savePath;
- }
- public void setSavePath(String savePath) {
- this.savePath = savePath;
- }
- public int getThreadNumber() {
- return threadNumber;
- }
- public void setThreadNumber(int threadNumber) {
- this.threadNumber = threadNumber;
- }
- public String getReferer() {
- return referer;
- }
- public void setReferer(String referer) {
- this.referer = referer;
- }
- }
- class HTTPDownloaderThread extends Thread {
- HTTPDownloader manager;
- int startPos;
- int endPos;
- int id;
- int curPos;
- int BUFFER_SIZE = 4096;
- int readByte = 0;
- HTTPDownloaderThread(HTTPDownloader manager, int id, int startPos, int endPos) {
- this.id = id;
- this.manager = manager;
- this.startPos = startPos;
- this.endPos = endPos;
- }
- public void run() {
-
-
- BufferedInputStream bis = null;
- RandomAccessFile fos = null;
-
- byte[] buf = new byte[BUFFER_SIZE];
- URLConnection con = null;
- try {
- File file = new File(manager.getSavePath());
-
- fos = new RandomAccessFile(file, "rw");
-
- fos.seek(startPos);
-
- URL url = new URL(manager.getPage());
- con = url.openConnection();
- con.setAllowUserInteraction(true);
- curPos = startPos;
-
- con.setRequestProperty("Range", "bytes=" + startPos + "-" + endPos);
-
- con.setRequestProperty("referer", manager.getReferer() == null ? manager.getPage() : manager.getReferer());
- con.setRequestProperty("userAgent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)");
-
-
- bis = new BufferedInputStream(con.getInputStream());
- while (curPos < endPos) {
- int len = bis.read(buf, 0, BUFFER_SIZE);
- if (len == -1) {
- break;
- }
- fos.write(buf, 0, len);
- curPos = curPos + len;
- if (curPos > endPos) {
-
- readByte += len - (curPos - endPos) + 1;
- } else {
- readByte += len;
- }
- }
-
- bis.close();
- fos.close();
- } catch (IOException ex) {
- ex.printStackTrace();
- }
- }
- }
二、做成Http的服务,侦听某个端口使用了JDK6的特性,大家自己看代码吧,并不复杂
- package net.java2000.tools;
- import java.io.IOException;
- import java.io.OutputStream;
- import java.net.InetSocketAddress;
- import java.net.URLDecoder;
- import java.util.regex.Matcher;
- import java.util.regex.Pattern;
- import com.sun.net.httpserver.HttpExchange;
- import com.sun.net.httpserver.HttpHandler;
- import com.sun.net.httpserver.HttpServer;
- import com.sun.net.httpserver.spi.HttpServerProvider;
- public class HTTPDownloadService {
-
- public static void main(String[] args) throws IOException {
- HttpServerProvider httpServerProvider = HttpServerProvider.provider();
- int port = 60080;
- if (args.length > 0) {
- try {
- port = Integer.parseInt(args[0]);
- } catch (Exception ex) {}
- }
-
- InetSocketAddress addr = new InetSocketAddress(port);
- HttpServer httpServer = httpServerProvider.createHttpServer(addr, 1);
- httpServer.createContext("/", new HTTPDownloaderServiceHandler());
- httpServer.setExecutor(null);
- httpServer.start();
- System.out.println("started");
- }
- }
- class HTTPDownloaderServiceHandler implements HttpHandler {
- private static Pattern p = Pattern.compile("\\?page=(.*?)\\&rpage=(.*?)&savepath=(.*)$");
- public void handle(HttpExchange httpExchange) {
- try {
- Matcher m = p.matcher(httpExchange.getRequestURI().toString());
- String response = "OK";
- if (m.find()) {
- try {
- new HTTPDownloader(URLDecoder.decode(m.group(1), "GBK"), URLDecoder.decode(m.group(2), "GBK"), URLDecoder.decode(m.group(3), "GBK"), 10).start();
- } catch (Exception e) {
- response = "ERROR -1";
- e.printStackTrace();
- }
- } else {
- response = "ERROR 1";
- }
- httpExchange.sendResponseHeaders(200, response.getBytes().length);
- OutputStream out = httpExchange.getResponseBody();
- out.write(response.getBytes());
- out.close();
- httpExchange.close();
- } catch (Exception ex) {
- ex.printStackTrace();
- }
- }
- }
这个程序可以单独运行的,通过
http://127.0.0.1:60080
访问,参数是固定顺序的,比如
http://127.0.0.1:60080?page=http://www.csdn.net&rpage=http://blog.csdn.net&savepath=d:/csdn.html
三个参数分别代表了
page = 被下载的页面
rpage = referer的页面,用来对付防盗链的系统
savepath = 下载后保存的文件
三、改造成Windows的服务主要使用了这个技术,不是很复杂
http://www.java2000.net/p598所需要的东西我已经全部提供,且提供了一个完整的zip包供下载学习和研究用。
下载地址和原文请看这里:
http://www.java2000.net/p9398总结:
希望对web变成有兴趣的,应该多了解一下HTTP协议,对于提高你的认知层次,注意不是水平,而是层次是有极大的帮助的。
<script type="text/javascript">
</script> <script src="http://pagead2.googlesyndication.com/pagead/show_ads.js" type="text/javascript">
</script>
分享到:
相关推荐
基于boost::asio的http server3修改的echo服务器,有多线程,多侦听端口,超时处理等
多线程 TCP/IP 侦听器
AccessPort 端口侦听 绿色 不用安装 不占用端口
ASP.NET Development Server未能开始侦听端口
多线程 TCIIP 侦听器(VB.NET).rar
单线程实现同时监听多个端口(windows平台c++代码)。文章查看https://www.cnblogs.com/yuanchenhui/p/icop_accept.html
网络端口监听与端口扫描技术 网络端口监听与端口扫描技术
多线程 TCIIP 侦听器(VB.NET)
可侦听本地已打开的TCP端口报文,需安装WinPcap,本资源已包含
商业编程-源码-端口侦听工具.zip
socket 服务器侦听socket 服务器侦听socket 服务器侦听socket 服务器侦听socket 服务器侦听socket 服务器侦听socket 服务器侦听socket 服务器侦听socket 服务器侦听socket 服务器侦听socket 服务器侦听socket 服务器...
简单 HTTP Web 客户端和多线程 Web 服务器的 Java 实现。 ###开发工具: 编程语言: Java (jdk 1.7) IDE: Eclipse Juno (4.2) 外部包:除了 java.io 和 java.net 等默认 Java 包之外,不需要任何外部包。 操作...
套接字代理一个简单的 Java 多线程 Socket 代理服务器。 它侦听传入的连接并将任何通信转发到服务器,同时记录整个对话。套接字代理服务器这是库的主类。 它可以由第三方实例化,并提供本地端口和服务器的远程主机/...
Veritas Backup Exec 侦听端口详细信息,
这个程序的功能类似于代理,起因是要接收UDP数据包,但不知道端口号,所以就写了这个可以侦听指定范围内所有端口的小程序。 另附测试用的数据包发送器和接收器。
计算机软件-商业源码-多线程 TCIIP 侦听器(VB.NET).zip
1、运用多线程和Socket技术实现Socket Server端侦听多个客户端请求; 2、实现服务器端循环处理客户端不同请求从而实现不同测试要求,并向客户端循环发送数据; 3、实现客户端向服务器端发送不同测试命令,并接收...
用于在服务器端侦听上传到服务器的数据。该工具是用C#编写的 ,使用的时候只要侦听端口号,以及要创建相应的数据库表。
VB.NET源码,多线程侦听器,CS结构的监听器,测试时候可以打开监听端,再启动客户端,此时客户端会开始发送测试消息,在监听端的窗口内你会发现这些测试信息。