国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > Java > 正文

Java基于Socket實現HTTP下載客戶端

2019-11-26 14:40:34
字體:
來源:轉載
供稿:網友

沒有借助任何第三方庫,完全基于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請求與響應。具體步驟

如下:

一、根據用戶輸入的文件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 <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程序設計有所幫助。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 剑川县| 伊吾县| 和田市| 安溪县| 威宁| 兴仁县| 两当县| 鹤壁市| 虞城县| 巨鹿县| 阿拉善左旗| 贡嘎县| 广平县| 确山县| 梅州市| 峨山| 韶关市| 芒康县| 江安县| 樟树市| 嘉定区| 额敏县| 柘荣县| 双辽市| 蓬安县| 东乌珠穆沁旗| 敦煌市| 定兴县| 青河县| 镇坪县| 嘉荫县| 常州市| 福州市| 宁阳县| 嘉祥县| 深水埗区| 资中县| 板桥市| 浑源县| 连城县| 凤山县|