Java基於Socket完成HTTP下載客戶端。本站提示廣大學習愛好者:(Java基於Socket完成HTTP下載客戶端)文章只能為提供參考,不一定能成為您想要的結果。以下是Java基於Socket完成HTTP下載客戶端正文
沒有借助任何第三方庫,完整基於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<DownloadDetailStatusInfoModel> downloadedList = new ArrayList<DownloadDetailStatusInfoModel>(); 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要求報文以下:
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要求與呼應。詳細步調
以下:
1、依據用戶輸出的文件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。
2、結構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";
3、發送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();
4、接收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 <status code, CharSet, ect...> * refer to RFC2616,關於HTTP呼應頭,請看RFC文檔,描述的很具體啊!! */ 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<String, String> headerMap; public HttpResponseHeaderParser() { headerMap = new HashMap<String, String>(); } /** * <p> get the response header key value pair </p> * @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<String, String> getAllHeaders() { return headerMap; } }
以上就是本文的全體內容,願望對年夜家的進修java法式設計有所贊助。