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

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

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

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

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

首先看一下UI部分:

0818b9ca8b590ca3270a3433284dd417.png

【添加下载】按钮:

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

下载

0818b9ca8b590ca3270a3433284dd417.png

【清除完成】按钮:

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

文件下载状态分为以下几种:

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请求报文如

0818b9ca8b590ca3270a3433284dd417.png

其中请求头可以有多个,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响应报文如下

0818b9ca8b590ca3270a3433284dd417.png

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

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

转载请务必注明

阅读终点,创作起航,您可以撰写心得或摘录文章要点写篇博文。去创作
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Java Socket编程是一种网络编程模型,它是建立在TCP/IP协议上的,允许在网络上进行数据通信。Java Socket编程提供了一种方便的方法,可以通过网络连接来传输数据。 以下是Java Socket编程的一些基本步骤: 1. 创建一个ServerSocket对象,指定口号,并监听客户请求。 2. 当客户请求连接时,ServerSocket会接收请求,并创建一个Socket对象,用于与客户进行通信。 3. 使用Socket对象的输入输出流来进行数据传输。 4. 客户与服务通信完成后,关闭Socket对象和ServerSocket对象。 下面是一个简单的Java Socket编程示例,用于创建一个简单的服务: ```java import java.net.*; import java.io.*; public class ServerSocketDemo { public static void main(String[] args) throws IOException { ServerSocket serverSocket = null; try { serverSocket = new ServerSocket(8088); System.out.println("Server started."); while (true) { Socket socket = serverSocket.accept(); System.out.println("Client connected."); // 从客户读取数据 InputStream inputStream = socket.getInputStream(); BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream)); String data = reader.readLine(); System.out.println("Received data from client: " + data); // 向客户发送数据 OutputStream outputStream = socket.getOutputStream(); PrintWriter writer = new PrintWriter(outputStream); writer.println("Hello, client!"); writer.flush(); // 关闭Socket对象 socket.close(); } } catch (IOException e) { System.out.println("Error: " + e.getMessage()); } finally { if (serverSocket != null) { serverSocket.close(); } } } } ``` 在上面的示例中,我们创建了一个ServerSocket对象,并指定口号为8088。然后,我们使用while循环来监听客户请求。当有客户请求连接时,我们使用serverSocket.accept()方法来接收请求,并创建一个Socket对象,用于与客户通信。接着,我们使用Socket对象的输入输出流来进行数据传输。最后,我们关闭Socket对象和ServerSocket对象。 这只是一个简单的示例,Java Socket编程还有很多其他用法和技巧。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

沃娃

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值