最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java基于Socket實(shí)現(xiàn)HTTP下載客戶端

 更新時(shí)間:2016年01月15日 16:50:27   作者:gloomyfish  
這篇文章主要介紹了Java基于Socket實(shí)現(xiàn)HTTP下載客戶端的相關(guān)資料,感興趣的小伙伴們可以參考一下

沒有借助任何第三方庫,完全基于JAVA Socket實(shí)現(xiàn)一個(gè)最小化的HTTP文件下載客戶端。完整的演示如何通過Socket實(shí)現(xiàn)下載文件的HTTP請(qǐng)求(request header)發(fā)送如何從Socket中接受HTTP響應(yīng)(Response header, Response body)報(bào)文并解析與保存文件內(nèi)容。如何通過SwingWork實(shí)現(xiàn)UI刷新,實(shí)時(shí)顯示下載進(jìn)度。

首先看一下UI部分:

【添加下載】按鈕:

點(diǎn)擊彈出URL輸入框,用戶Copy要下載文件URL到輸入框以后,點(diǎn)擊[OK]按鈕即開始

下載


【清除完成】按鈕:

清除所有已經(jīng)下載完成的文件列表

文件下載狀態(tài)分為以下幾種:

package com.gloomyfish.socket.tutorial.http.download; 
 
public enum DownLoadStatus { 
  NOT_STARTED, 
  IN_PROCESS, 
  COMPLETED, 
  ERROR 
} 

UI部分主要是利用Swing組件完成。點(diǎn)擊【添加下載】執(zhí)行的代碼如下:

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); 

【清除完成】按鈕執(zhí)行的代碼如下:

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協(xié)議實(shí)現(xiàn)部分:

概述:HTTP請(qǐng)求頭與相應(yīng)頭報(bào)文基本結(jié)構(gòu)與解釋

HTTP請(qǐng)求:一個(gè)標(biāo)準(zhǔn)的HTTP請(qǐng)求報(bào)文如


其中請(qǐng)求頭可以有多個(gè),message-body可以沒有,不是必須的。請(qǐng)求行的格式如下:

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

當(dāng)你想要上傳文件時(shí)候,使用Post方式來填寫數(shù)據(jù)到message-body中即可。發(fā)送一個(gè)

簡(jiǎn)單的HTTP請(qǐng)求報(bào)文如下:

HTTP響應(yīng):一個(gè)標(biāo)準(zhǔn)的HTTP響應(yīng)報(bào)文如下


最先得到是狀態(tài)行,其格式如下:

Status-Line = HTTP-Version SP Status-CodeSP Reason-Phrase CRLF, 一個(gè)狀態(tài)行的簡(jiǎn)單例子如下:Status-Line = HTTP/1.1 200 OK一般大家最喜歡的就是Status-Code會(huì)給你很多提示,最常見的就是404,500等狀態(tài)碼。狀態(tài)碼的意思可以參考RFC2616中的解釋。下載文件最要緊是的檢查HTTP響應(yīng)頭中的Content-Length與Content-Type兩

個(gè)中分別聲明了文件的長(zhǎng)度與文件的類型。其它如Accept-Ranges表示接受多少到多少的字節(jié)。可能在多線程下載中使用。搞清楚了HTTP請(qǐng)求與響應(yīng)的報(bào)文格式以后,我們就可以通過Socket按照?qǐng)?bào)文格式解析內(nèi)容,發(fā)送與讀取HTTP請(qǐng)求與響應(yīng)。具體步驟

如下:

一、根據(jù)用戶輸入的文件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變成容易解析一點(diǎn)的URL。
二、構(gòu)造HTTP請(qǐng)求

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 - 構(gòu)造HTTP請(qǐng)求頭(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"; 

三、發(fā)送HTTP請(qǐng)求

// 發(fā)送HTTP請(qǐng)求 
bufferedWriter.write(requestStr); 
bufferedWriter.write(hostHeader); 
bufferedWriter.write(acceptHeader); 
bufferedWriter.write(charsetHeader); 
bufferedWriter.write(languageHeader); 
bufferedWriter.write(keepHeader); 
bufferedWriter.write("\r\n"); // 請(qǐng)求頭信息發(fā)送結(jié)束標(biāo)志 
bufferedWriter.flush(); 

四、接受HTTP響應(yīng)并解析內(nèi)容,寫入創(chuàng)建好的文件

// 準(zhǔn)備接受HTTP響應(yīng)頭并解析 
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; 
  } 
} 

簡(jiǎn)單的HTTP響應(yīng)頭解析類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,關(guān)于HTTP響應(yīng)頭,請(qǐng)看RFC文檔,描寫的很詳細(xì)?。?! 
 */ 
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; 
  } 
 
} 

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)java程序設(shè)計(jì)有所幫助。

相關(guān)文章

  • 基于Redis生成分布式全局唯一ID的3種策略

    基于Redis生成分布式全局唯一ID的3種策略

    在分布式系統(tǒng)設(shè)計(jì)中,全局唯一ID是一個(gè)基礎(chǔ)而關(guān)鍵的組件,Redis具備高性能、原子操作及簡(jiǎn)單易用的特性,因此我們可以基于Redis實(shí)現(xiàn)全局唯一ID的生成,下面我們來看看實(shí)現(xiàn)的三種方法吧
    2025-04-04
  • Java獲取mac地址的方法

    Java獲取mac地址的方法

    這篇文章主要介紹了Java獲取mac地址的方法,涉及java針對(duì)系統(tǒng)硬件及IO操作的相關(guān)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-07-07
  • idea?springBoot項(xiàng)目自動(dòng)注入mapper為空?qǐng)?bào)錯(cuò)的解決方法

    idea?springBoot項(xiàng)目自動(dòng)注入mapper為空?qǐng)?bào)錯(cuò)的解決方法

    這篇文章主要介紹了idea?springBoot項(xiàng)目自動(dòng)注入mapper為空?qǐng)?bào)錯(cuò)的解決方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-03-03
  • 深入理解final變量的初始化

    深入理解final變量的初始化

    本篇文章是對(duì)final變量的初始化進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下
    2013-06-06
  • Java中的HashMap弱引用之WeakHashMap詳解

    Java中的HashMap弱引用之WeakHashMap詳解

    這篇文章主要介紹了Java中的HashMap弱引用之WeakHashMap詳解,當(dāng)內(nèi)存空間不足,Java虛擬機(jī)寧愿拋出OutOfMemoryError錯(cuò)誤,使程序異常終止,也不會(huì)靠隨意回收具有強(qiáng)引用的對(duì)象來解決內(nèi)存不足的問題,需要的朋友可以參考下
    2023-09-09
  • servlet之session工作原理簡(jiǎn)介_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理

    servlet之session工作原理簡(jiǎn)介_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理

    這篇文章主要介紹了servlet之session工作原理簡(jiǎn)介,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-07-07
  • IDEA?中配置?Gradle?和安裝使用教程

    IDEA?中配置?Gradle?和安裝使用教程

    Gradle本身是基于Groovy腳本語言進(jìn)行構(gòu)建的,并通過 Domain Specific Language(DSL 語言)進(jìn)行描述和控制構(gòu)建邏輯,本文重介紹了IDEA?中配置?Gradle?和使用,需要的朋友可以參考下
    2023-10-10
  • 詳解spring mvc中url-pattern的寫法

    詳解spring mvc中url-pattern的寫法

    這篇文章主要介紹了spring mvc中url-pattern的寫法,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-12-12
  • Spring Boot右鍵maven build成功但是直接運(yùn)行main方法出錯(cuò)的解決方案

    Spring Boot右鍵maven build成功但是直接運(yùn)行main方法出錯(cuò)的解決方案

    這篇文章主要介紹了Spring Boot-右鍵maven build成功但是直接運(yùn)行main方法出錯(cuò)的解決方案,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-08-08
  • Spring Boot Admin郵件警報(bào)整合過程解析

    Spring Boot Admin郵件警報(bào)整合過程解析

    這篇文章主要介紹了Spring Boot Admin郵件警報(bào)整合過程解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-03-03

最新評(píng)論

高碑店市| 闽清县| 合阳县| 泽普县| 霸州市| 武夷山市| 遵义县| 当雄县| 兴安盟| 安平县| 晋中市| 财经| 利辛县| 民权县| 柘荣县| 高淳县| 黄骅市| 策勒县| 清镇市| 磐安县| 浦江县| 彰化市| 察隅县| 中牟县| 荔波县| 日照市| 上栗县| 双桥区| 凤凰县| 弋阳县| 富平县| 明水县| 德格县| 山西省| 泌阳县| 神木县| 陵川县| 通山县| 伽师县| 涟水县| 潜江市|