一个网友正好需要这个东西,我就把几个技术整合到了一起。包括三个部分,实现时也是逐个做到的
- 多线程的文件下载,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>
分享到:
相关推荐
在IT领域,多线程TCP/IP侦听器是一种常见的网络通信技术,特别是在开发服务器端应用程序时。本篇文章将深入探讨这个主题,重点关注VB.NET环境下的实现。 首先,TCP/IP(Transmission Control Protocol/Internet ...
《基于Boost.ASIO的HTTP Server3:多线程、多端口与超时处理的Echo服务器实现》 Boost.ASIO是C++库中的一个强大组件,...通过对多线程、多端口监听和超时处理的理解,我们可以更好地理解和构建高性能的网络应用程序。
端口侦听意味着一个进程正在等待来自网络的数据,表明该端口上的服务已经启动并准备好接收连接。 在商业编程中,端口侦听工具的应用场景包括: 1. **服务监控**:检查服务器上的服务是否正常运行,例如Web服务器、...
在IT领域,多线程TCP/IP侦听器是一种常见的网络通信工具,用于接收并处理来自多个客户端的并发连接。在VB.NET环境下,开发者可以利用System.Net.Sockets命名空间中的TcpListener类来实现这样的功能。本节将深入探讨...
AccessPort 端口侦听是一款实用的网络监控工具,主要功能是帮助用户监测和分析计算机上特定端口的活动。作为一个绿色软件,它无需安装即可使用,这意味着它不包含额外的注册表项或者系统服务,因此不会占用不必要的...
压缩包中的"Sniffer.exe"很可能是端口侦听程序的可执行文件,用户运行这个文件就可以启动程序来监听本地端口。而"readme.txt"文件通常是提供软件使用说明、安装步骤或注意事项的文档,用户在使用前应仔细阅读,以...
标题提到的"单线程实现同时监听多个端口"是一种优化技术,它避免了为每个端口创建一个单独的线程,从而减少了系统资源的消耗。这种技术主要依赖于Windows的IO完成端口(I/O Completion Ports, IOCP)机制,它能高效地...
这个“多线程TCPIP侦听器”示例旨在演示如何利用VB.NET实现高效且稳定的网络通信。 首先,我们需要理解TCP/IP协议。TCP(传输控制协议)是一种面向连接的、可靠的、基于字节流的传输层通信协议,而IP(互联网协议)...
此外,`java.net.ServerSocket`类也可以用来侦听特定端口,但这个通常用于创建服务器端应用,而不是扫描端口。对于端口扫描,`Socket`类是更合适的工具。 注意,频繁地扫描大量端口可能会被视为网络攻击,因此在...
在VB.NET编程环境中,创建一个多线程TCP监听器是一项重要的任务,特别是在处理大量并发连接时,多线程技术能够显著提升程序的性能和响应能力。这个“多线程TCPIP侦听器”项目可能涉及以下几个核心知识点: 1. **TCP...
`UDPServerDriver`可能是主驱动类,负责启动和管理UDP服务器,而`UDPServerLinkspool`可能是一个链接池类,用于管理和复用UDP连接,提高服务器的性能。 综上所述,通过Java的DatagramSocket类,我们可以实现UDP的...
网络端口监听与端口扫描技术 网络端口监听与端口扫描技术
### Java开发环境Eclipse远程调试端口配置 #### 运行环境配置 为了实现Java Eclipse远程调试功能,首先需要确保本地开发环境与远程服务器环境之间的兼容性和一致性。具体步骤如下: 1. **运行ncSysconfig命令**:...
ASP.NET Development Server未能开始侦听端口
扫描程序的优点是使用了多线程技术和非阻塞 I/O,可以同时扫描多个端口,从而加速扫描速度。另一个好处是用户不需要任何权限,系统中的任何用户都有权利使用这个调用。 然而,扫描程序的缺点是很容易被发觉,并且被...
在IT领域,VB.NET是一种基于.NET Framework的编程语言,它...通过研究和理解这个代码,开发者不仅可以学习到VB.NET中的多线程技术,还可以深入理解网络通信的基本原理,这对于构建分布式系统或网络应用是非常有价值的。
在多线程TCP/IP侦听器的实现中,开发者可能会用到以下关键概念和技术: 1. **System.Net.Sockets命名空间**:VB.NET中用于TCP/IP通信的核心类库,包含TcpListener和TcpClient类。 2. **多线程**:使用Thread类创建并...
总的来说,C#的多线程和Socket通信是构建高效、实时网络应用的基础,理解并熟练掌握这些技术对于任何IT开发者来说都是至关重要的。通过实践这样的项目,我们可以加深对网络编程的理解,提高解决问题的能力。
它不仅提供了一个稳定、高效的自动侦听机制,还通过多线程技术解决了多串口通信中遇到的并发问题。开发者通过学习和使用这一程序,可以深入掌握串口通信、多线程编程和设备交互的知识,为未来处理更加复杂的系统集成...
端口侦听工具是一种用于监控网络通信的软件,它能够帮助用户查看哪些程序正在通过特定端口进行数据传输。在IT行业中,这类工具通常被网络安全专家、系统管理员以及开发者用来诊断网络问题、检测潜在的入侵行为或者...