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

使用HttpHandler实现文件下载页面 示例: Hello,HttpHandler(最简单的HttpHandler) -------------------------------------------------------------------------------- 示例: 使用HttpHandler实现文件下载页面 -------------------------------------------------------------------------------- 示例: 添加图片访问的HttpHandler,为网站图片提供"水印" 立即下载

一个网友正好需要这个东西,我就把几个技术整合到了一起。包括三个部分,实现时也是逐个做到的
  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.youkuaiyun.com&rpage=http://blog.youkuaiyun.com&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" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"> </script>
将springboot打包成的jar文件做成windows服务,解决java程序自启动问题 将springboot打包成的jar文件做成windows服务,解决java程序自启动问题,适合现场部署后无人看管情况,断电后服务器启动后不用管理springboot服务,不用打开cmd,也不担心现场人员误操作关闭cmd窗口。 立即下载

相关推荐

利用Windows Server 2008 创建Domain Controller.

利用Windows Server 2008 创建Domain Controller.

Java 网络编程 —— 创建非阻塞的 HTTP 服务器

HTTP 客户程序必须先发出一个 HTTP 请求,然后才能接收到来自 HTTP 服器的响应,浏览器就是最常见的 HTTP 客户程序。HTTP 客户程序和 HTTP 服务器分别由不同的软件开发商提供,它们都可以用任意的编程语言编写。HTTP 严格规定了 HTTP 请求和 HTTP 响应的数据格式,只要 HTTP 服务器与客户程序都遵守 HTTP,就能彼此看得懂对方发送的消息。

低吟不作语的博客 1792

surfer10与Arcgis10.3 完美生成等值线和等值面方法

surfer10 与Arcgis10.3生成等值线和等值面的步骤如下: 1.准备surfer用的Book1.dat文件,格式如下: "x" "y" "z" 116.471992 40.809975 232 116.335556 40.700542 1235 116.541626 40.713333 214 116.73349 40.798607 566 2.在surfer中,选择Gr

哈里·雪利博客 1万+

java语言实现一个多线程的HTTP服务器

主程序: package com.xuyu; import java.net.ServerSocket; import java.net.Socket; public class httpServer implements Runnable{ private static Boolean isRun = true; private static Boolean isPush = true; public static String resourcePath = "";.

xy294636185的博客 757

01_MySQL下载、安装与配置(以MySQL8.0.31版本为例)

1.点击下载好的mysql安装包 进入到mysql installer界面。2.选择MySQL Servers选项 一直下拉。

4822

MCGS触摸屏Modbus TCP通讯实战:从寄存器写入到字符串处理的完整代码解析

本文详细解析了MCGS触摸屏通过Modbus TCP协议实现寄存器写入和字符串处理的完整代码,涵盖单寄存器写入、多寄存器写入及字符串传输等核心技术。文章还提供了MCGS组态环境中的实战配置步骤和常见问题排查方法,帮助开发者快速掌握工业自动化通讯的关键技术。

study的专栏 760

Lotus notes问题与处理

关于出现“Server Controller未在主机上运行或未在端口2050侦听”的错误 @FJR : 参考文档 #1449200 Unable to start the Domino 852 server as a service and run the Java Controller on Windows 2008 R2 server. URL: http://www.ibm.c...

bluecard2008的博客 3678

【抖音】a_bogus参数逆向分析

点击——展开xxx条回复﹀就会出现。可以看到这个栈是有请求相关的数据的。所以就是在bdms.js里面生成的。

qq_44990881的博客 3000

关于出现“Server Controller未在主机上运行或未在端口2050侦听”的错误

2019独角兽企业重金招聘Python工程师标准>>> ...

weixin_34331102的博客 764

YOLO11涨点优化:原创自研 | 魔改Bottleneck,具备多尺度和特征通道融合的结构

可以将C3k2_MSAMCS放在neck,或者backbone和neck同时修改,具体看自己数据集的涨点情况决定

①答疑群聊服务;②YOLO大模型知识问答系统;③计算机视觉论文生成智能体; 1653

【数据结构与算法基础】05. 栈详解(C++ 实战)

本文介绍了栈(Stack)的基本概念、特点和应用场景。栈是一种遵循后进先出(LIFO)原则的线性数据结构,主要操作包括push、pop、peek等。文章详细讲解了顺序栈(基于数组)和链式栈(基于链表)两种实现方式,对比了它们的优缺点,并提供了完整的C++实现代码。栈广泛应用于函数调用、表达式求值、深度优先搜索等场景,是计算机科学中重要的基础数据结构。

yuhuasheng1997的博客 1280

在Windows 2008 R2上,Domino服务器无法作为服务来运行,Java控制台也无法启动

 Technote (troubleshooting) 问题 在Windows 2008 R2上,Domino服务器无法作为服务来运行,Java控制台也无法启动 症状 当管理员尝试启动 Lotus Domino 控制台,(即:Java Controller for Domino) 时,报告以下错误: "Either the Server Controller

Gavid0124的专栏 3558

Agentic AI为教育行业赋能,提示工程架构师解析应用潜力

然而,即便是最先进的 LLMs,在面对复杂、动态、需要持续规划和调整的教育场景时,也常常显得力不从心,它们更像是强大的“问答机器”,而非真正意义上的“学习伙伴”或“教学助手”。在教育场景中,传统的 AI 工具可能只能回答学生提出的特定问题,或者根据预设的规则推送一些学习材料。无论您是教育技术领域的开发者、产品经理,还是一线的教育工作者、教育管理者,抑或是对 AI 教育应用充满好奇的研究者,本文都将为您提供宝贵的 insights,助您把握 Agentic AI 时代教育创新的脉搏。

架构师的AI之路,分享AI应用开发架构的学习与实践。 467

java http请求 多线程_java模拟多线程http请求代码分享

java模拟http发送请求,第一种是HttpURLConnection发送post请求,第二种是使用httpclient模拟post请求,实例代码:package test;import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map;import java.util....

weixin_34365042的博客 646

华为od 面试八股文_JAVA语言_01_含答案

华为od 面试八股文_JAVA语言_01_含答案

MISAYAONE的博客 4319

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

java http监听_一个基于Socket的http请求监听程序实现

首先来看以下我们的需求:用java编写一个监听程序,监听指定的端口,通过浏览器如http://localhost:7777来访问时,可以把请求到的内容记录下来,记录可以存文件,sqlit,mysql数据库,然后把接受到的信息在浏览器中显示出来要点:Socket,线程,数据库,IO操作,观察者模式来看下我们如何来设计这个小系统,这个系统包含三部分的内容,一个是监听端口,二是记录日志,三是数据回显,端...

Aysen的博客 2981

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

Asp.Net底层解析(五)——HttpHandler详解

前言:上一篇博客详细介绍了应用程序生命周期与HttpModule。在HttpApplication对象启动HTTP管线阶段的PreRequestHandlerExecute与PostRequestHandlerExecute事件之间,实际上就是根据所请求资源的文件扩展名(在应用程序的配置文件中映射),选择实现 IHttpHandler 的类,调用该类的ProcessRequest方法,从而得到该请

mlcactus的专栏 3747

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

HttpHandler 服务接口启动与配置(支持JSON、xml传输)

HttpHandler 服务接口启动与配置(支持JSON、xml传输) 第一步:接口启动(可配置bean 进行初始化服务启动) 一、接口 public class ICBCServer { // 加载服务器地址 private static String server_URL = Env.getPropertyValuByName(“ICBC_Server_URL”); //加载服务器端口 private static String server_Port = Env.getPropertyValuByN

weixin_50921815的博客 486

机房搬迁AIX系统调研指令模板

1查看机器型号SN   查看机器型号,SN DB2Server[/]#uname -Mu IBM,9117-MMA IBM,02065D746             2查看操作系统版本---便于解决问题和重装OS   查看系统的maintenance level    DB2Server[/]#oslevel -s 5300-

Jesse的黑洞 4967

java httphandler_一般处理程序HttpHandler的应用

namespaceWeb.HttpHandler{public classLoginHandler : IHttpHandler, IRequiresSessionState{public voidProcessRequest(HttpContext context){context.Response.ContentType= "text/plain";string sReturnJson = s...

weixin_29170327的博客 698

HttpHandler详解

概述 HttpHandler是一个HTTP请求的真正处理中心,也正是在这个HttpHandler容器中,ASP.NET Framework才真正地对客户端请求的服务器页面做出编译和执行,并将处理过后的信息附加在HTTP请求信息流中再次返回到HttpModule中。 IHttpHandler是什么 IHttpHandler定义了如果要实现一个HTTP请求的处理所必需实现的一些系统约定。Ht

Keymo_的奋斗史 1万+
上一篇: [转]Microsoft SQL Server 2008 安装图集
下一篇: 构造函数有没有返回值的总结
老紫竹
博客等级 码龄19年 1万+粉丝 1252原创
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值