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

Http學(xué)習(xí)之組裝報(bào)文

 更新時(shí)間:2023年04月28日 08:41:44   作者:CrazyDragon_King  
這篇文章主要介紹了Http學(xué)習(xí)之組裝報(bào)文,組裝報(bào)文就是指組裝HTTP響應(yīng)報(bào)文,你需要返回客戶請(qǐng)求的相應(yīng)資源,通常一個(gè)完整的報(bào)文包括報(bào)文頭和報(bào)文體,一起來看看吧

前面介紹了一些,基本的概念和需要具備的編程知識(shí)。下面開始來進(jìn)行代碼的編寫,前面已經(jīng)提到了最終的代碼會(huì)是一個(gè)的http服務(wù)器的小demo–一個(gè)圖床網(wǎng)站。

主要目標(biāo)介紹

這里主要涉及的知識(shí)點(diǎn)就是解析報(bào)文和組裝報(bào)文。 解析報(bào)文就是指解析HTTP請(qǐng)求報(bào)文,你需要知道報(bào)文請(qǐng)求的資源是什么。 組裝報(bào)文就是指組裝HTTP響應(yīng)報(bào)文,你需要返回客戶請(qǐng)求的相應(yīng)資源。

目標(biāo)分析

解析報(bào)文,需要獲取完整的報(bào)文,利用報(bào)文的特定結(jié)構(gòu),獲取報(bào)文里面的信息。然后依據(jù)這些信息,先客戶端返回響應(yīng)報(bào)文。這里涉及到自己解析報(bào)文,比較有難度,因?yàn)樾枰獔?bào)文的結(jié)構(gòu)特定。上一篇博客已經(jīng)簡(jiǎn)單介紹過了(這里只是處理一些簡(jiǎn)單的請(qǐng)求和響應(yīng)報(bào)文,不是那種特別復(fù)雜的,畢竟只是學(xué)習(xí),沒有必要自己和自己過不去?。?/p>

組裝報(bào)文,需要將客戶需要的信息組裝好,然后發(fā)送給客戶端。報(bào)文會(huì)由客戶端(通常是瀏覽器)自動(dòng)解析,這里就不需要解析了,只是把報(bào)文發(fā)送給客戶端。對(duì)于編程來說,只是涉及到IO流的處理而已。所以,組裝報(bào)文比較簡(jiǎn)單一些。

所以,這篇博客就先只介紹如何組裝報(bào)文(注意這里雖然是簡(jiǎn)單的報(bào)文,但也是符合規(guī)定的報(bào)文)。

組裝報(bào)文

我們來回顧一下前面介紹的知識(shí),通常一個(gè)完整的報(bào)文包括報(bào)文頭和報(bào)文體。(當(dāng)然了,GET請(qǐng)求方式是沒有請(qǐng)求體的。)

主要的代碼就是下面三行了。

out.write(header);        //寫入Http報(bào)文頭部部分
out.write(content);       //寫入Http報(bào)文數(shù)據(jù)部分
out.flush();              //刷新輸出流,確保緩沖區(qū)內(nèi)數(shù)據(jù)已經(jīng)發(fā)送完成

是不是感覺很神奇,所謂的HTTP報(bào)文,在TCP這個(gè)層次來看,不過就是一個(gè)字節(jié)流。(這里 header 和 content 在網(wǎng)絡(luò)上是可以看成串行的流。)

啟動(dòng)服務(wù)類

這個(gè)類和平時(shí)使用的 ServerSocket 類用法沒有什么區(qū)別,就是使用多線程來處理每一個(gè)客戶端的連接。啟動(dòng)一個(gè)ServerSocket,監(jiān)聽10000端口。

package com.dragon;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class HttpServer {
	private static ServerSocket server;
	
	/**
	 * 啟動(dòng)服務(wù)
	 * */
	public void start() {
	    try {
	    	server = new ServerSocket(10000);
	    	System.out.println("服務(wù)啟動(dòng)成功...");
	    	this.receiveRequest();
	    } catch (IOException e) {
	    	e.printStackTrace();
	    	System.out.println("服務(wù)啟動(dòng)失??!");
	    }
	}

	
	/**
	 * 接收請(qǐng)求
	 * */
	public void receiveRequest() {
		ExecutorService pool = Executors.newFixedThreadPool(10);
		while (true) {
			try {
				Socket client = server.accept();
				System.out.println("用戶"+client.getInetAddress().toString()+"建立連接" + client.toString());
				pool.submit(new Connection(client));  //使用線程處理每一個(gè)請(qǐng)求。
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
	
	/**
	 * 停止服務(wù)
	 * 注:一般是不需要關(guān)閉服務(wù)的。
	 * */
	public void stop() {
		try {
			if (server != null) {
				server.close();
			}
		} catch (IOException e) {
			e.printStackTrace();
			System.out.println("服務(wù)器關(guān)閉失?。?);
		}
	}
}

連接類

對(duì)于每一個(gè)客戶端的連接,獲取用戶的請(qǐng)求,并返回響應(yīng)。因?yàn)橹皇且粋€(gè)簡(jiǎn)單的模擬,這里其實(shí)獲取用戶的請(qǐng)求也不進(jìn)行處理(因?yàn)樘幚硇枰馕稣?qǐng)求報(bào)文),對(duì)于任何的請(qǐng)求返回的響應(yīng)都是同一個(gè)。所以,它實(shí)際上還具有一個(gè)非常有趣的特點(diǎn)–消滅了404。 相信經(jīng)常使用瀏覽器的人應(yīng)該都知道404這個(gè)錯(cuò)誤吧,404的意思是對(duì)于當(dāng)前的請(qǐng)求沒有找到請(qǐng)求的資源。所以,通??梢钥吹?Not Found 這兩個(gè)英文單詞,當(dāng)然了也可以自定義成其它的形式。因?yàn)檫@個(gè)程序,只具有接收請(qǐng)求,返回響應(yīng)的基本功能,所以,我間接消滅了404,哈哈!

注:頭部字段中,我只是返回了幾個(gè)必要的頭部。因?yàn)镠TTP頭部還是比較多的,有些也不是必要的。具體的信息,可以參考一些專業(yè)的書籍來了解更多的知識(shí)或者直接閱讀這方面的權(quán)威–RFC文檔,哈哈(不過我也沒有看,就是瞅了一眼。)。

package com.dragon;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;

public class Connection implements Runnable {
	private static final String BLANK = " ";
	private static final String CRLF = "\r\n";
	private byte[] content;
	private byte[] header;
	private Socket client;
	
	public Connection(Socket client) {
		this.client = client;
	}
	
	@Override
	public void run() {
		//這里不對(duì)請(qǐng)求進(jìn)行處理,只是收到請(qǐng)求之后會(huì)進(jìn)行響應(yīng),而不管是什么請(qǐng)求
		//這里模擬服務(wù)器最原始的功能:請(qǐng)求、響應(yīng)。
		this.response();
		System.out.println("線程執(zhí)行結(jié)束了!");
	}
	
	/**
	 * 接收請(qǐng)求信息,這里只是一個(gè)簡(jiǎn)單的模擬,這里只能接收get請(qǐng)求。
	 * @throws IOException 
	 * */
	public String getRequestInfo(InputStream in) throws IOException {
		//只讀取第一行,這是我們需要的全部內(nèi)容
		StringBuilder requestLine = new StringBuilder(80);
		while (true) {
			int c = in.read();
			if (c == '\r' || c == '\n' || c == -1) break;
			requestLine.append((char)c);
		}
		return requestLine.toString();
	}
	
	/**
	 * 響應(yīng)信息
	 * */
	public void response() {
		InputStream in = null;
		OutputStream out = null; 
		try {
			in = new BufferedInputStream(client.getInputStream());
			out = new BufferedOutputStream(client.getOutputStream());   //獲取輸出流
			String requestInfo = this.getRequestInfo(in);           //如果不讀取客戶端發(fā)來的數(shù)據(jù),服務(wù)器就會(huì)出錯(cuò)。
			System.out.println(requestInfo);
		} catch (IOException e1) {
			e1.printStackTrace();
		}       //獲取輸入流
		
		
		//響應(yīng)體數(shù)據(jù)
		File file = new File("D:/DragonFile/target/attitude.jpg");
		String contentType = null;  //文件的 MIME 類型
		try {
			content = Files.readAllBytes(file.toPath());           //使用 Files 工具類,一次性讀取文件
			contentType = Files.probeContentType(file.toPath());   //獲取文件的 MIME 類型
			long length = file.length();                           //獲取文件字節(jié)長度
			header = this.getHeader(contentType, length);          // 填充響應(yīng)頭
 		} catch (IOException e) {
			e.printStackTrace();
		}
		
		try {
			out.write(header);        //寫入Http報(bào)文頭部部分
			out.write(content);       //寫入Http報(bào)文數(shù)據(jù)部分
			out.flush();              //刷新輸出流,確保緩沖區(qū)內(nèi)數(shù)據(jù)已經(jīng)發(fā)送完成
			
			System.out.println("報(bào)文總大小(字節(jié)):" + (header.length + content.length));
		} catch (IOException e) {
			e.printStackTrace();
			System.out.println("客戶斷開連接或者發(fā)送失??!");
		} finally {
			//此處關(guān)閉 client 會(huì)導(dǎo)致程序出現(xiàn)問題,但是原因不清楚。
			try {
				if (client != null) {
					client.close();
				}
				System.out.println("請(qǐng)求結(jié)束了");
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
    }
	
	//響應(yīng)頭
	private byte[] getHeader(String contentType, long length) {
		return new StringBuilder()
				.append("HTTP/1.1").append(BLANK).append(200).append(BLANK).append("OK").append(CRLF)  // 響應(yīng)頭部
				.append("Server:"+"CrazyDragon").append(CRLF)
				.append("Date:").append(BLANK).append(this.getDate()).append(CRLF)
				.append("Content-Type:").append(BLANK).append(contentType).append(CRLF) //文件的 Content-Type 可通過Java獲取。
				.append("Content-Length:").append(BLANK).append(length).append(CRLF).append(CRLF)
				.toString()
				.getBytes(Charset.forName("UTF-8"));
	}
	
	//獲取時(shí)間
	private String getDate() {
		Date date = new Date();
		SimpleDateFormat format = new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss 'GMT'", Locale.US);
		format.setTimeZone(TimeZone.getTimeZone("GMT")); // 設(shè)置時(shí)區(qū)為GMT  
		return format.format(date);
	}
}


主類

package com.dragon;

public class Test {
	public static void main(String[] args) {
		HttpServer httpServer = new HttpServer();
		httpServer.start();
	}
}

運(yùn)行結(jié)果

打印輸出:

在這里插入圖片描述

瀏覽器訪問:

在這里插入圖片描述

注:上面可以看到會(huì)有兩個(gè)請(qǐng)求,這是因?yàn)闉g覽器訪問的時(shí)候,會(huì)請(qǐng)求網(wǎng)站的圖標(biāo),通常的路徑為 /favicon.ico,這里似乎是因?yàn)榫彺妫瑳]有看到它的請(qǐng)求,如果存在請(qǐng)求行應(yīng)該為:GET /favicon.ico HTTP/1.1。

隨便訪問一個(gè)地址,看一看沒有404的網(wǎng)站!

在這里插入圖片描述

訪問結(jié)果

在這里插入圖片描述

注意:這里可能會(huì)遇到異常。 但是這個(gè)對(duì)于程序的運(yùn)行結(jié)果沒有影響。報(bào)錯(cuò)的原因處在這句話:out.wirte(content);

在這里插入圖片描述

可能的原因有一下幾點(diǎn):

①:服務(wù)器的并發(fā)連接數(shù)超過了其承載量,服務(wù)器會(huì)將其中一些連接Down掉;

②:客戶關(guān)掉了瀏覽器,而服務(wù)器還在給客戶端發(fā)送數(shù)據(jù);

③:瀏覽器端按了Stop 按鈕。

④:用servlet的outputstream輸出流下載圖片時(shí),當(dāng)用戶點(diǎn)擊取消也會(huì)報(bào)這個(gè)錯(cuò)誤。

總結(jié)

目前,組裝報(bào)文這個(gè)功能已經(jīng)實(shí)現(xiàn)了,現(xiàn)在已經(jīng)很有意思了吧。通過這個(gè)簡(jiǎn)單的程序,已經(jīng)可以真正理解為什么HTTP是建立在TCP協(xié)議之上的了吧。這里我特別選了一張圖片來進(jìn)行展示,效果應(yīng)該還是很不錯(cuò)的。

到此這篇關(guān)于Http學(xué)習(xí)之組裝報(bào)文的文章就介紹到這了,更多相關(guān)Http組裝報(bào)文內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java簡(jiǎn)化復(fù)雜系統(tǒng)調(diào)用的門面設(shè)計(jì)模式

    Java簡(jiǎn)化復(fù)雜系統(tǒng)調(diào)用的門面設(shè)計(jì)模式

    Java門面模式是一種結(jié)構(gòu)性設(shè)計(jì)模式,它為復(fù)雜系統(tǒng)提供了一個(gè)簡(jiǎn)單的接口,使得系統(tǒng)的客戶端能夠更加方便地使用系統(tǒng)功能。門面模式通過封裝復(fù)雜的子系統(tǒng),隱藏系統(tǒng)的實(shí)現(xiàn)細(xì)節(jié),提高了系統(tǒng)的易用性和靈活性
    2023-04-04
  • dependencies導(dǎo)致的Maven依賴出錯(cuò)包紅問題解決方法

    dependencies導(dǎo)致的Maven依賴出錯(cuò)包紅問題解決方法

    多模塊和分布式開發(fā)一般都是有專門的的dependencies來進(jìn)行jar包的版本依賴問題,本文主要介紹了dependencies導(dǎo)致的Maven依賴出錯(cuò)包紅問題解決方法,具有一定的參考價(jià)值,感興趣的可以了解一下
    2022-05-05
  • executor包執(zhí)行器功能

    executor包執(zhí)行器功能

    這篇文章主要介紹了executor包執(zhí)行器功能,executor包中的各個(gè)子包提供的功能,最終這些功能都由Executor接口及其實(shí)現(xiàn)類共同對(duì)外提供服務(wù)。下文介紹該執(zhí)行功能,具有一定的參考價(jià)值,需要的朋友可以考一下
    2022-02-02
  • Java刪除文件、目錄及目錄下所有文件的方法實(shí)例

    Java刪除文件、目錄及目錄下所有文件的方法實(shí)例

    這篇文章主要給大家介紹了關(guān)于利用Java刪除文件、目錄及目錄下所有文件的方法,文中給出了詳細(xì)的示例代碼與注解,有需要的朋友可以參考借鑒,下面來一起看看吧。
    2016-12-12
  • 詳解ssh框架原理及流程

    詳解ssh框架原理及流程

    在本文中小編給大家整理的是關(guān)于ssh框架原理及流程的相關(guān)知識(shí)點(diǎn)內(nèi)容,有此需要的朋友們可以學(xué)習(xí)下。
    2019-07-07
  • 在Spring Boot2中使用CompletableFuture的方法教程

    在Spring Boot2中使用CompletableFuture的方法教程

    這篇文章主要給大家介紹了關(guān)于在Spring Boot2中使用CompletableFuture的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起看看吧
    2019-01-01
  • java string類方法深入解析

    java string類方法深入解析

    以下是對(duì)java中的string類方法進(jìn)行了詳細(xì)的分析介紹。需要的朋友可以過來參考下
    2013-08-08
  • java實(shí)現(xiàn)響應(yīng)重定向發(fā)送post請(qǐng)求操作示例

    java實(shí)現(xiàn)響應(yīng)重定向發(fā)送post請(qǐng)求操作示例

    這篇文章主要介紹了java實(shí)現(xiàn)響應(yīng)重定向發(fā)送post請(qǐng)求操作,結(jié)合實(shí)例形式分析了java請(qǐng)求響應(yīng)、重定向及數(shù)據(jù)處理相關(guān)操作技巧,需要的朋友可以參考下
    2020-04-04
  • MyBatis學(xué)習(xí)教程(四)-如何快速解決字段名與實(shí)體類屬性名不相同的沖突問題

    MyBatis學(xué)習(xí)教程(四)-如何快速解決字段名與實(shí)體類屬性名不相同的沖突問題

    我們經(jīng)常會(huì)遇到表中的字段名和表對(duì)應(yīng)實(shí)體類的屬性名稱不一定都是完全相同的情況,如何解決呢?下面腳本之家小編給大家介紹MyBatis學(xué)習(xí)教程(四)-如何快速解決字段名與實(shí)體類屬性名不相同的沖突問題,一起學(xué)習(xí)吧
    2016-05-05
  • SpringBoot+MinIO實(shí)現(xiàn)文件切片極速詳解

    SpringBoot+MinIO實(shí)現(xiàn)文件切片極速詳解

    在現(xiàn)代Web應(yīng)用中,文件上傳是一個(gè)常見的需求,尤其是對(duì)于大文件的上傳,如視頻、音頻或大型文檔,所以本文就來為大家介紹一下如何使用Spring Boot和MinIO實(shí)現(xiàn)文件切片極速上傳技術(shù)吧
    2023-12-12

最新評(píng)論

安仁县| 辰溪县| 娄烦县| 五常市| 阿城市| 宜兰县| 东宁县| 潞西市| 菏泽市| 宁河县| 威海市| 齐河县| 中江县| 四子王旗| 保亭| 清远市| 色达县| 固阳县| 三门县| 石阡县| 陕西省| 黎平县| 西和县| 长阳| 卓资县| 屏南县| 定安县| 马尔康县| 太原市| 汽车| 玉门市| 武强县| 固安县| 福建省| 绩溪县| 镇江市| 仪征市| 德保县| 乌兰察布市| 同德县| 攀枝花市|