没有借助任何第三方库,完全基于JAVA Socket实现一个最小化的HTTP文件下载客

户端。完整的演示如何通过Socket实现下载文件的HTTP请求(request header)发送

如何从Socket中接受HTTP响应(Response header, Response body)报文并解析与

保存文件内容。如何通过SwingWork实现UI刷新,实时显示下载进度。

首先看一下UI部分:

【添加下载】按钮:

点击弹出URL输入框,用户Copy要下载文件URL到输入框以后,点击[OK]按钮即开始

下载

【清除完成】按钮:

清除所有已经下载完成的文件列表

文件下载状态分为以下几种: package com.gloomyfish.socket.tutorial.http.download; public enum DownLoadStatus { NOT_STARTED, IN_PROCESS, COMPLETED, ERROR }

UI部分主要是利用Swing组件完成。点击【添加下载】执行的代码如下: final JDialog dialog = new JDialog(this,"Add File Link",true); dialog.getContentPane().setLayout(new BorderLayout()); // dialog.setSize(new Dimension(400,200)); final URLFilePanel panel = new URLFilePanel(); panel.setUpListener(new ActionListener(){ @Override public void actionPerformed(ActionEvent e) { if("OK".equals(e.getActionCommand())){ if(panel.validateInput()) { DownloadDetailStatusInfoModel data = new DownloadDetailStatusInfoModel(panel.getValidFileURL()); tableModel.getData().add(data); startDownlaod(); refreshUI(); } dialog.setVisible(false); dialog.dispose(); } else if("Cancel".equals(e.getActionCommand())) { dialog.setVisible(false); dialog.dispose(); } }}); dialog.getContentPane().add(panel, BorderLayout.CENTER); dialog.pack(); centre(dialog); dialog.setVisible(true);【清除完成】按钮执行的代码如下:

private void clearDownloaded() { List downloadedList = new ArrayList(); for(DownloadDetailStatusInfoModel fileStatus : tableModel.getData()) { if(fileStatus.getStatus().toString().equals(DownLoadStatus.COMPLETED.toString())) { downloadedList.add(fileStatus); } } tableModel.getData().removeAll(downloadedList); refreshUI(); }让JFrame组件居中显示的代码如下:

public static void centre(Window w) { Dimension us = w.getSize(); Dimension them = Toolkit.getDefaultToolkit().getScreenSize(); int newX = (them.width - us.width) / 2; int newY = (them.height - us.height) / 2; w.setLocation(newX, newY); }

HTTP协议实现部分:

概述:HTTP请求头与相应头报文基本结构与解释

HTTP请求:一个标准的HTTP请求报文如

其中请求头可以有多个,message-body可以没有,不是必须的。请求行的格式如下:

Request-Line = Method SP Request-URI SPHTTP-Version CRLF 举例说明如下:

Request-Line = GET http://www.w3.org/pub/WWW/TheProject.htmlHTTP/1.1\r\n

其中SP表示空格, CRLF表示回车换行符\r\n

当你想要上传文件时候,使用Post方式来填写数据到message-body中即可。发送一个

简单的HTTP请求报文如下:

GET /pub/WWW/TheProject.html HTTP/1.1\r\n

\r\n

HTTP响应:一个标准的HTTP响应报文如下

最先得到是状态行,其格式如下:

Status-Line = HTTP-Version SP Status-CodeSP Reason-Phrase CRLF, 一个状态行的

简单例子如下:Status-Line = HTTP/1.1 200 OK一般大家最喜欢的就是Status-Code会

给你很多提示,最常见的就是404,500等状态码。状态码的意思可以参考RFC2616中

的解释。下载文件最要紧是的检查HTTP响应头中的Content-Length与Content-Type两

个中分别声明了文件的长度与文件的类型。其它如Accept-Ranges表示接受多少到多少

的字节。可能在多线程下载中使用。搞清楚了HTTP请求与响应的报文格式以后,我们

就可以通过Socket按照报文格式解析内容,发送与读取HTTP请求与响应。具体步骤

如下:

一:根据用户输入的文件URL建立Socket连接

URL url = new URL(fileInfo.getFileURL()); String host = url.getHost(); int port = (url.getPort() == -1) ? url.getDefaultPort():url.getPort(); System.out.println("Host Name = " + host); System.out.println("port = " + port); System.out.println("File URI = " + url.getFile()); // create socket and start to construct the request line Socket socket = new Socket(); SocketAddress address = new InetSocketAddress(host, port); socket.connect(address);用了URL类来把用户输入的url string变成容易解析一点的URL。

二:构造HTTP请求

BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(), "UTF8")); String requestStr = "GET " + url.getFile() + " HTTP/1.1\r\n"; // request line // construct the request header - 构造HTTP请求头(request header) String hostHeader = "Host: " + host + "\r\n"; String acceptHeader = "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n"; String charsetHeader = "Accept-Charset: GBK,utf-8;q=0.7,*;q=0.3\r\n"; String languageHeader = "Accept-Language: zh-CN,zh;q=0.8\r\n"; String keepHeader = "Connection: close\r\n";三:发送HTTP请求// 发送HTTP请求 bufferedWriter.write(requestStr); bufferedWriter.write(hostHeader); bufferedWriter.write(acceptHeader); bufferedWriter.write(charsetHeader); bufferedWriter.write(languageHeader); bufferedWriter.write(keepHeader); bufferedWriter.write("\r\n"); // 请求头信息发送结束标志 bufferedWriter.flush();

四:接受HTTP响应并解析内容,写入创建好的文件 // 准备接受HTTP响应头并解析 CustomDataInputStream input = new CustomDataInputStream(socket.getInputStream()); File myFile = new File(fileInfo.getStoreLocation() + File.separator + fileInfo.getFileName()); String content = null; HttpResponseHeaderParser responseHeader = new HttpResponseHeaderParser(); BufferedOutputStream output = new BufferedOutputStream(new FileOutputStream(myFile)); boolean hasData = false; while((content = input.readHttpResponseHeaderLine()) != null) { System.out.println("response header contect -->> " + content); responseHeader.addResponseHeaderLine(content); if(content.length() == 0) { hasData = true; } if(hasData) { int totalBytes = responseHeader.getFileLength(); if(totalBytes == 0) break; // no response body and data int offset = 0; byte[] myData = null; if(totalBytes >= 2048) { myData = new byte[2048]; } else { myData = new byte[totalBytes]; } int numOfBytes = 0; while((numOfBytes = input.read(myData, 0, myData.length)) > 0 && offset < totalBytes) { offset += numOfBytes; float p = ((float)offset) / ((float)totalBytes) * 100.0f; if(offset > totalBytes) { numOfBytes = numOfBytes + totalBytes - offset; p = 100.0f; } output.write(myData, 0, numOfBytes); updateStatus(p); } hasData = false; break; } }简单的HTTP响应头解析类HttpResponseHeaderParser代码如下:

package com.gloomyfish.socket.tutorial.http.download; import java.util.HashMap; import java.util.Map; /** * it can parse entity header, response head * and response line * refer to RFC2616,关于HTTP响应头,请看RFC文档,描写的很详细啊!! * * @author fish * */ public class HttpResponseHeaderParser { public final static String CONTENT_LENGTH = "Content-Length"; public final static String CONTENT_TYPE = "Content-Type"; public final static String ACCEPT_RANGES = "Accetp-Ranges"; private Map headerMap; public HttpResponseHeaderParser() { headerMap = new HashMap(); } /** *

get the response header key value pair

* @param responseHeaderLine */ public void addResponseHeaderLine(String responseHeaderLine) { if(responseHeaderLine.contains(":")) { String[] keyValue = responseHeaderLine.split(": "); if(keyValue[0].equalsIgnoreCase(CONTENT_LENGTH)) { headerMap.put(CONTENT_LENGTH, keyValue[1]); } else if(keyValue[0].equalsIgnoreCase(CONTENT_TYPE)) { headerMap.put(CONTENT_TYPE, keyValue[1]); } else { headerMap.put(keyValue[0], keyValue[1]); } } } public int getFileLength() { if(headerMap.get(CONTENT_LENGTH) == null){ return 0; } return Integer.parseInt(headerMap.get(CONTENT_LENGTH)); } public String getFileType() { return headerMap.get(CONTENT_TYPE); } public Map getAllHeaders() { return headerMap; } }

可执行的Jar文件下载地址(这次我要点分):

http://download.csdn.net/detail/jia20003/4862076

转载请务必注明

java socket 实现 http_Java Socket编程 - 基于Socket实现HTTP下载客户端相关推荐

  1. java socket 传输压缩文件_java基于socket传输zip文件功能示例

    本文实例讲述了java基于socket传输zip文件的方法.分享给大家供大家参考,具体如下: 服务器端程序: import java.io.*; import java.net.*; import j ...

  2. 基于UDP协议的socket套接字编程 基于socketserver实现并发的socket编程

    基于UDP协议 的socket套接字编程 1.UDP套接字简单示例 1.1服务端 import socketserver = socket.socket(socket.AF_INET,socket.S ...

  3. Java领域的对象如何传输-基于 socket 进行对象传输

    先举个简单的例子,基于我们前面几次课程的只是,写一个socket通信的代码 User public class User { private String name; public String ge ...

  4. socket网络编程——基于socket通信实现对客户端与服务器间的文件互传

    客户端与服务器间的文件互传 基于socket的文件数据互传,将文件中所有的字符一一通过buf进行传递,为了更好地判断文件的 结束,通过添加文件结束标识符"#",当接收端接收到该字符 ...

  5. python socket 网络聊天室_Python基于Socket实现简单聊天室

    本文实例为大家分享了Python基于Socket实现简单聊天室,供大家参考,具体内容如下 服务端 #!/usr/bin/env python # -*- coding: utf-8 -*- # @Ti ...

  6. java socket编程客户端_Java Socket编程 - 基于Socket实现HTTP下载客户端

    没有借助任何第三方库,完全基于JAVA Socket实现一个最小化的HTTP文件下载客 户端.完整的演示如何通过Socket实现下载文件的HTTP请求(request header)发送 如何从Soc ...

  7. JAVA基础知识之网络编程——-基于AIO的异步Socket通信

    异步IO 下面摘子李刚的<疯狂JAVA讲义> 按照POSIX标准来划分IO,分为同步IO和异步IO.对于IO操作分为两步,1)程序发出IO请求. 2)完成实际的IO操作. 阻塞IO和非阻塞 ...

  8. 学习笔记(05):Python网络编程并发编程-基于socket实现简单套接字通信

    立即学习:https://edu.csdn.net/course/play/24458/296234?utm_source=blogtoedu 1.服务器端 #以打电话通讯为例子进行说明 #导入相应的 ...

  9. Java之初步识别网络编程:IP、端口号、TCP/UDP、Socket、URL等

    文章目录 一.网络编程概述 二.网络通信要素概述 三.通信要素1:IP和端口号 IP相关 InetAdress类 如何实例化InetAddress 端口号 四.通信要素2:网络协议 TCP/IP协议簇 ...

最新文章

  1. 【每日一算法】最常见的单词
  2. 秒懂上线必不可少的安全测试!
  3. Micropython开发实例之TPYBoard v702GPRS功能测试
  4. C# MVC中返回JSON 对象
  5. 关于企业信息化中审计流程“寻租”现象的探讨
  6. linux 编译链接图
  7. 30是什么意思_“29+16”变“30+18”是什么意思?独立艺术院校有何优势?报考需要注意什么?...
  8. java设置默认参数_关于java:如何设置默认方法参数值?
  9. python中控制代码块逻辑关系_一、Python基础知识
  10. 产品心经:产品经理应该知道的60件事
  11. 如何Python写一个安卓APP
  12. 2019年win10最精简版本——win10企业2019长期服务版本下载和激活密钥
  13. 汉字转拼音,多音字解决方案
  14. 基于Spring的MVC框架设计与实现
  15. SICP-Notes-Lecture 19 Macros
  16. 获取非行内样式的兼容
  17. 什么是EDM营销?EDM营销和一般营销方式的区别分析
  18. matlab日常(2)
  19. loadrunner11.0 安装 破解
  20. 【数量技术宅|量化投资策略系列分享】成熟交易者期货持仓跟随策略

热门文章

  1. App后台开发运维和架构实践学习总结(13)——OAuth 2.0 概述流程理解
  2. Beetl学习总结(4)——Web集成
  3. Dubbo学习总结(3)——Dubbo-Admin管理平台和Zookeeper注册中心的搭建
  4. Dubbo学习总结(1)——Dubbo入门基础与实例讲解
  5. mysql和sqlserver读写分离_C#简单构架之EF进行读写分离+多数据库Mysql/SqlServer
  6. 我用系统的思想来编程
  7. “安防+人工智能”,安企选择哪种抱大腿姿势才有出息?
  8. 简单的线路的界面的调用方法
  9. Unity3d之求物体体积
  10. 某大型IT公司招网络工程师认证试题精选(要求:CCNA或 HCNE以上)