`
逆风的香1314
  • 浏览: 1419580 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Java技术体验,HTTP多线程下载,端口侦听和自启动服务

阅读更多

一个网友正好需要这个东西,我就把几个技术整合到了一起。包括三个部分,实现时也是逐个做到的
  1. 多线程的文件下载,HTTP协议
  2. 把这个功能做成一个HTTP的服务,侦听在某个端口上,方便非Java的系统使用
  3. 把这个功能封装为一个Windows服务,在机器启动时可以自动启动

我们逐个看程序。

一、多线程下载

这个主要使用了HTTP协议里面的一个Range参数,他设置了你读取数据的其实位置和终止位置。 经常使用flashget的用户在查看连接的详细信息时,应该经常看到这个东西。比如

Range:bytes=100-2000

代表从100个字节的位置开始读取,到2000个字节的位置结束,应读取1900个字节。

程序首先拿到文件的长度,然后分配几个线程去分别读取各自的一段,使用了
RandomAccessFile
进行随机位置的读写。

下面是完整的下载的代码。
  1. package net.java2000.tools;
  2. import java.io.BufferedInputStream;
  3. import java.io.File;
  4. import java.io.IOException;
  5. import java.io.RandomAccessFile;
  6. import java.net.URL;
  7. import java.net.URLConnection;
  8. /**
  9.  * HTTP的多线程下载工具。
  10.  * 
  11.  * @author 赵学庆 www.java2000.net
  12.  */
  13. public class HTTPDownloader extends Thread {
  14.   // 要下载的页面
  15.   private String page;
  16.   // 保存的路径
  17.   private String savePath;
  18.   // 线程数
  19.   private int threadNumber = 2;
  20.   // 来源地址
  21.   private String referer;
  22.   // 最小的块尺寸。如果文件尺寸除以线程数小于这个,则会减少线程数。
  23.   private int MIN_BLOCK = 10 * 1024;
  24.   public static void main(String[] args) throws Exception {
  25.     HTTPDownloader d = new HTTPDownloader("http://www.xxxx.net/xxxx.rar""d://xxxx.rar"10);
  26.     d.down();
  27.   }
  28.   public void run() {
  29.     try {
  30.       down();
  31.     } catch (Exception e) {
  32.       e.printStackTrace();
  33.     }
  34.   }
  35.   /**
  36.    * 下载操作
  37.    * 
  38.    * @throws Exception
  39.    */
  40.   public void down() throws Exception {
  41.     URL url = new URL(page); // 创建URL
  42.     URLConnection con = url.openConnection(); // 建立连接
  43.     int contentLen = con.getContentLength(); // 获得资源长度
  44.     if (contentLen / MIN_BLOCK + 1 < threadNumber) {
  45.       threadNumber = contentLen / MIN_BLOCK + 1// 调整下载线程数
  46.     }
  47.     if (threadNumber > 10) {
  48.       threadNumber = 10;
  49.     }
  50.     int begin = 0;
  51.     int step = contentLen / threadNumber;
  52.     int end = 0;
  53.     for (int i = 0; i < threadNumber; i++) {
  54.       end += step;
  55.       if (end > contentLen) {
  56.         end = contentLen;
  57.       }
  58.       new HTTPDownloaderThread(this, i, begin, end).start();
  59.       begin = end;
  60.     }
  61.   }
  62.   public HTTPDownloader() {
  63.   }
  64.   /**
  65.    * 下载
  66.    * 
  67.    * @param page 被下载的页面
  68.    * @param savePath 保存的路径
  69.    */
  70.   public HTTPDownloader(String page, String savePath) {
  71.     this(page, savePath, 10);
  72.   }
  73.   /**
  74.    * 下载
  75.    * 
  76.    * @param page 被下载的页面
  77.    * @param savePath 保存的路径
  78.    * @param threadNumber 线程数
  79.    */
  80.   public HTTPDownloader(String page, String savePath, int threadNumber) {
  81.     this(page, page, savePath, 10);
  82.   }
  83.   /**
  84.    * 下载
  85.    * 
  86.    * @param page 被下载的页面
  87.    * @param savePath 保存的路径
  88.    * @param threadNumber 线程数
  89.    * @param referer 来源
  90.    */
  91.   public HTTPDownloader(String page, String referer, String savePath, int threadNumber) {
  92.     this.page = page;
  93.     this.savePath = savePath;
  94.     this.threadNumber = threadNumber;
  95.     this.referer = referer;
  96.   }
  97.   public String getPage() {
  98.     return page;
  99.   }
  100.   public void setPage(String page) {
  101.     this.page = page;
  102.   }
  103.   public String getSavePath() {
  104.     return savePath;
  105.   }
  106.   public void setSavePath(String savePath) {
  107.     this.savePath = savePath;
  108.   }
  109.   public int getThreadNumber() {
  110.     return threadNumber;
  111.   }
  112.   public void setThreadNumber(int threadNumber) {
  113.     this.threadNumber = threadNumber;
  114.   }
  115.   public String getReferer() {
  116.     return referer;
  117.   }
  118.   public void setReferer(String referer) {
  119.     this.referer = referer;
  120.   }
  121. }
  122. /**
  123.  * 下载线程
  124.  * 
  125.  * @author 赵学庆 www.java2000.net
  126.  */
  127. class HTTPDownloaderThread extends Thread {
  128.   HTTPDownloader manager;
  129.   int startPos;
  130.   int endPos;
  131.   int id;
  132.   int curPos;
  133.   int BUFFER_SIZE = 4096;
  134.   int readByte = 0;
  135.   HTTPDownloaderThread(HTTPDownloader manager, int id, int startPos, int endPos) {
  136.     this.id = id;
  137.     this.manager = manager;
  138.     this.startPos = startPos;
  139.     this.endPos = endPos;
  140.   }
  141.   public void run() {
  142.     // System.out.println("线程" + id + "启动");
  143.     // 创建一个buff
  144.     BufferedInputStream bis = null;
  145.     RandomAccessFile fos = null;
  146.     // 缓冲区大小
  147.     byte[] buf = new byte[BUFFER_SIZE];
  148.     URLConnection con = null;
  149.     try {
  150.       File file = new File(manager.getSavePath());
  151.       // 创建RandomAccessFile
  152.       fos = new RandomAccessFile(file, "rw");
  153.       // 从startPos开始
  154.       fos.seek(startPos);
  155.       // 创建连接,这里会为每个线程都创建一个连接
  156.       URL url = new URL(manager.getPage());
  157.       con = url.openConnection();
  158.       con.setAllowUserInteraction(true);
  159.       curPos = startPos;
  160.       // 设置获取资源数据的范围,从startPos到endPos
  161.       con.setRequestProperty("Range""bytes=" + startPos + "-" + endPos);
  162.       // 盗链解决
  163.       con.setRequestProperty("referer", manager.getReferer() == null ? manager.getPage() : manager.getReferer());
  164.       con.setRequestProperty("userAgent""Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)");
  165.       // 下面一段向根据文件写入数据,curPos为当前写入的未知,这里会判断是否小于endPos,
  166.       // 如果超过endPos就代表该线程已经执行完毕
  167.       bis = new BufferedInputStream(con.getInputStream());
  168.       while (curPos < endPos) {
  169.         int len = bis.read(buf, 0, BUFFER_SIZE);
  170.         if (len == -1) {
  171.           break;
  172.         }
  173.         fos.write(buf, 0, len);
  174.         curPos = curPos + len;
  175.         if (curPos > endPos) {
  176.           // 获取正确读取的字节数
  177.           readByte += len - (curPos - endPos) + 1;
  178.         } else {
  179.           readByte += len;
  180.         }
  181.       }
  182.       // System.out.println("线程" + id + "已经下载完毕:" + readByte);
  183.       bis.close();
  184.       fos.close();
  185.     } catch (IOException ex) {
  186.       ex.printStackTrace();
  187.     }
  188.   }
  189. }


二、做成Http的服务,侦听某个端口
使用了JDK6的特性,大家自己看代码吧,并不复杂
  1. package net.java2000.tools;
  2. import java.io.IOException;
  3. import java.io.OutputStream;
  4. import java.net.InetSocketAddress;
  5. import java.net.URLDecoder;
  6. import java.util.regex.Matcher;
  7. import java.util.regex.Pattern;
  8. import com.sun.net.httpserver.HttpExchange;
  9. import com.sun.net.httpserver.HttpHandler;
  10. import com.sun.net.httpserver.HttpServer;
  11. import com.sun.net.httpserver.spi.HttpServerProvider;
  12. /**
  13.  * 下载程序的服务版本。<br>
  14.  * 可以供其它程序调用,而不是局限于java
  15.  * 
  16.  * @author 赵学庆 www.java2000.net
  17.  */
  18. public class HTTPDownloadService {
  19.   /**
  20.    * @param args
  21.    * @throws IOException
  22.    */
  23.   public static void main(String[] args) throws IOException {
  24.     HttpServerProvider httpServerProvider = HttpServerProvider.provider();
  25.     int port = 60080;
  26.     if (args.length > 0) {
  27.       try {
  28.         port = Integer.parseInt(args[0]);
  29.       } catch (Exception ex) {}
  30.     }
  31.     // 绑定端口
  32.     InetSocketAddress addr = new InetSocketAddress(port);
  33.     HttpServer httpServer = httpServerProvider.createHttpServer(addr, 1);
  34.     httpServer.createContext("/"new HTTPDownloaderServiceHandler());
  35.     httpServer.setExecutor(null);
  36.     httpServer.start();
  37.     System.out.println("started");
  38.   }
  39. }
  40. /**
  41.  * 下载的服务器
  42.  * 
  43.  * @author 赵学庆 www.java2000.net
  44.  */
  45. class HTTPDownloaderServiceHandler implements HttpHandler {
  46.   private static Pattern p = Pattern.compile("\\?page=(.*?)\\&rpage=(.*?)&savepath=(.*)$");
  47.   public void handle(HttpExchange httpExchange) {
  48.     try {
  49.       Matcher m = p.matcher(httpExchange.getRequestURI().toString());
  50.       String response = "OK";
  51.       if (m.find()) {
  52.         try {
  53.           new HTTPDownloader(URLDecoder.decode(m.group(1), "GBK"), URLDecoder.decode(m.group(2), "GBK"), URLDecoder.decode(m.group(3), "GBK"), 10).start();
  54.         } catch (Exception e) {
  55.           response = "ERROR -1";
  56.           e.printStackTrace();
  57.         }
  58.       } else {
  59.         response = "ERROR 1";
  60.       }
  61.       httpExchange.sendResponseHeaders(200, response.getBytes().length);
  62.       OutputStream out = httpExchange.getResponseBody();
  63.       out.write(response.getBytes());
  64.       out.close();
  65.       httpExchange.close();
  66.     } catch (Exception ex) {
  67.       ex.printStackTrace();
  68.     }
  69.   }
  70. }

这个程序可以单独运行的,通过
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>
分享到:
评论

相关推荐

    多线程 TCIIP 侦听器

    在IT领域,多线程TCP/IP侦听器是一种常见的网络通信技术,特别是在开发服务器端应用程序时。本篇文章将深入探讨这个主题,重点关注VB.NET环境下的实现。 首先,TCP/IP(Transmission Control Protocol/Internet ...

    基于boost::asio的http server3修改的echo服务器,有多线程,多侦听端口,超时处理等

    《基于Boost.ASIO的HTTP Server3:多线程、多端口与超时处理的Echo服务器实现》 Boost.ASIO是C++库中的一个强大组件,...通过对多线程、多端口监听和超时处理的理解,我们可以更好地理解和构建高性能的网络应用程序。

    商业编程-源码-端口侦听工具.zip

    端口侦听意味着一个进程正在等待来自网络的数据,表明该端口上的服务已经启动并准备好接收连接。 在商业编程中,端口侦听工具的应用场景包括: 1. **服务监控**:检查服务器上的服务是否正常运行,例如Web服务器、...

    多线程 TCP/IP 侦听器

    在IT领域,多线程TCP/IP侦听器是一种常见的网络通信工具,用于接收并处理来自多个客户端的并发连接。在VB.NET环境下,开发者可以利用System.Net.Sockets命名空间中的TcpListener类来实现这样的功能。本节将深入探讨...

    AccessPort 端口侦听

    AccessPort 端口侦听是一款实用的网络监控工具,主要功能是帮助用户监测和分析计算机上特定端口的活动。作为一个绿色软件,它无需安装即可使用,这意味着它不包含额外的注册表项或者系统服务,因此不会占用不必要的...

    网络端口侦听程序,侦听本地打开端口的报文

    压缩包中的"Sniffer.exe"很可能是端口侦听程序的可执行文件,用户运行这个文件就可以启动程序来监听本地端口。而"readme.txt"文件通常是提供软件使用说明、安装步骤或注意事项的文档,用户在使用前应仔细阅读,以...

    单线程实现同时监听多个端口(windows平台c++代码)

    标题提到的"单线程实现同时监听多个端口"是一种优化技术,它避免了为每个端口创建一个单独的线程,从而减少了系统资源的消耗。这种技术主要依赖于Windows的IO完成端口(I/O Completion Ports, IOCP)机制,它能高效地...

    事例_多线程 TCIIP 侦听器(VB.NET)

    这个“多线程TCPIP侦听器”示例旨在演示如何利用VB.NET实现高效且稳定的网络通信。 首先,我们需要理解TCP/IP协议。TCP(传输控制协议)是一种面向连接的、可靠的、基于字节流的传输层通信协议,而IP(互联网协议)...

    java 扫描TCP端口

    此外,`java.net.ServerSocket`类也可以用来侦听特定端口,但这个通常用于创建服务器端应用,而不是扫描端口。对于端口扫描,`Socket`类是更合适的工具。 注意,频繁地扫描大量端口可能会被视为网络攻击,因此在...

    多线程 TCIIP 侦听器(VB.NET)

    在VB.NET编程环境中,创建一个多线程TCP监听器是一项重要的任务,特别是在处理大量并发连接时,多线程技术能够显著提升程序的性能和响应能力。这个“多线程TCPIP侦听器”项目可能涉及以下几个核心知识点: 1. **TCP...

    UDP.rar_UDP_UDP侦听_UDP发送_UDP接收_java接收端口

    `UDPServerDriver`可能是主驱动类,负责启动和管理UDP服务器,而`UDPServerLinkspool`可能是一个链接池类,用于管理和复用UDP连接,提高服务器的性能。 综上所述,通过Java的DatagramSocket类,我们可以实现UDP的...

    网络端口监听与端口扫描技术

    网络端口监听与端口扫描技术 网络端口监听与端口扫描技术

    多串口自动侦听程序

    "多串口自动侦听程序"是一个专为此设计的应用程序,它允许用户同时监控和管理多个串行端口的状态和数据流量。这个程序实例的出现,为开发者提供了一个方便的工具,尤其在需要处理多个串口设备交互的场合,例如工业...

    Java开发环境Eclipse远程调试端口配置

    ### Java开发环境Eclipse远程调试端口配置 #### 运行环境配置 为了实现Java Eclipse远程调试功能,首先需要确保本地开发环境与远程服务器环境之间的兼容性和一致性。具体步骤如下: 1. **运行ncSysconfig命令**:...

    ASP.NET Development Server未能开始侦听端口

    ASP.NET Development Server未能开始侦听端口

    一个简单的端口扫描程序题

    扫描程序的优点是使用了多线程技术和非阻塞 I/O,可以同时扫描多个端口,从而加速扫描速度。另一个好处是用户不需要任何权限,系统中的任何用户都有权利使用这个调用。 然而,扫描程序的缺点是很容易被发觉,并且被...

    VB.NET源码,多线程侦听器.rar

    在IT领域,VB.NET是一种基于.NET Framework的编程语言,它...通过研究和理解这个代码,开发者不仅可以学习到VB.NET中的多线程技术,还可以深入理解网络通信的基本原理,这对于构建分布式系统或网络应用是非常有价值的。

    计算机软件-商业源码-多线程 TCIIP 侦听器(VB.NET).zip

    在多线程TCP/IP侦听器的实现中,开发者可能会用到以下关键概念和技术: 1. **System.Net.Sockets命名空间**:VB.NET中用于TCP/IP通信的核心类库,包含TcpListener和TcpClient类。 2. **多线程**:使用Thread类创建并...

    C#多线程与Socket聊天室的实现

    总的来说,C#的多线程和Socket通信是构建高效、实时网络应用的基础,理解并熟练掌握这些技术对于任何IT开发者来说都是至关重要的。通过实践这样的项目,我们可以加深对网络编程的理解,提高解决问题的能力。

    这是一个端口侦听工具软件代码,功能很强,请谨慎使用(11kb)

    端口侦听工具是一种用于监控网络通信的软件,它能够帮助用户查看哪些程序正在通过特定端口进行数据传输。在IT行业中,这类工具通常被网络安全专家、系统管理员以及开发者用来诊断网络问题、检测潜在的入侵行为或者...

Global site tag (gtag.js) - Google Analytics