網路程式設計知識(5)--用Netty實現的一個簡單的HTTP伺服器
用Netty實現的一個簡單的HTTP伺服器,可以處理靜態檔案,例子中的註釋也比較全。
public class HttpServer {
public static void main(String[] args) {
ServerBootstrap bootstrap = new ServerBootstrap(new NioServerSocketChannelFactory(
Executors.newCachedThreadPool(), Executors.newCachedThreadPool()));
bootstrap.setPipelineFactory(new HttpServerPipelineFactory());
bootstrap.bind(new InetSocketAddress(8080));
System.out.println("伺服器已經啟動,請訪問http://127.0.0.1:8080/index.html進行測試!\n\n");
}
}
2.Pipeline
public class HttpServerPipelineFactory implements ChannelPipelineFactory {
public ChannelPipeline getPipeline () throws Exception {
// Create a default pipeline implementation.
ChannelPipeline pipeline = pipeline();
// Uncomment the following line if you want HTTPS
// SSLEngine engine =
// SecureChatSslContextFactory.getServerContext().createSSLEngine();
// engine.setUseClientMode(false);
// pipeline.addLast("ssl", new SslHandler(engine));
pipeline.addLast("decoder", new HttpRequestDecoder());
// Uncomment the following line if you don't want to handle HttpChunks.
// pipeline.addLast("aggregator", new HttpChunkAggregator(1048576));
pipeline.addLast("encoder", new HttpResponseEncoder());
// Remove the following line if you don't want automatic content
// compression.
//pipeline.addLast("aggregator", new HttpChunkAggregator(1048576));
pipeline.addLast("chunkedWriter", new ChunkedWriteHandler());
pipeline.addLast("deflater", new HttpContentCompressor());
pipeline.addLast("handler", new HttpRequestHandler());
return pipeline;
}
}
3.handler類
import static org.jboss.netty.handler.codec.http.HttpHeaders.is100ContinueExpected;
import static org.jboss.netty.handler.codec.http.HttpHeaders.isKeepAlive;
import static org.jboss.netty.handler.codec.http.HttpHeaders.Names.CONTENT_LENGTH;
import static org.jboss.netty.handler.codec.http.HttpHeaders.Names.COOKIE;
import static org.jboss.netty.handler.codec.http.HttpHeaders.Names.SET_COOKIE;
import static org.jboss.netty.handler.codec.http.HttpResponseStatus.CONTINUE;
import static org.jboss.netty.handler.codec.http.HttpResponseStatus.OK;
import static org.jboss.netty.handler.codec.http.HttpVersion.HTTP_1_1;
import java.io.File;
import java.io.RandomAccessFile;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelFutureListener;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.ExceptionEvent;
import org.jboss.netty.channel.MessageEvent;
import org.jboss.netty.channel.SimpleChannelUpstreamHandler;
import org.jboss.netty.handler.codec.http.Cookie;
import org.jboss.netty.handler.codec.http.CookieDecoder;
import org.jboss.netty.handler.codec.http.CookieEncoder;
import org.jboss.netty.handler.codec.http.DefaultHttpResponse;
import org.jboss.netty.handler.codec.http.HttpChunk;
import org.jboss.netty.handler.codec.http.HttpChunkTrailer;
import org.jboss.netty.handler.codec.http.HttpHeaders;
import org.jboss.netty.handler.codec.http.HttpMethod;
import org.jboss.netty.handler.codec.http.HttpRequest;
import org.jboss.netty.handler.codec.http.HttpResponse;
import org.jboss.netty.handler.codec.http.HttpResponseStatus;
import org.jboss.netty.handler.codec.http.QueryStringDecoder;
import org.jboss.netty.handler.stream.ChunkedFile;
import org.jboss.netty.util.CharsetUtil;
public class HttpRequestHandler extends SimpleChannelUpstreamHandler {
private HttpRequest request;
private boolean readingChunks;
@Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
if (!readingChunks) {
HttpRequest request = this.request = (HttpRequest) e.getMessage();
String uri = request.getUri();
System.out.println("-----------------------------------------------------------------");
System.out.println("uri:"+uri);
System.out.println("-----------------------------------------------------------------");
/**
* 100 Continue
* 是這樣的一種情況:HTTP客戶端程式有一個實體的主體部分要傳送給伺服器,但希望在傳送之前檢視下伺服器是否會
* 接受這個實體,所以在傳送實體之前先發送了一個攜帶100
* Continue的Expect請求首部的請求。伺服器在收到這樣的請求後,應該用 100 Continue或一條錯誤碼來進行響應。
*/
if (is100ContinueExpected(request)) {
send100Continue(e);
}
// 解析http頭部
for (Map.Entry<String, String> h : request.getHeaders()) {
System.out.println("HEADER: " + h.getKey() + " = " + h.getValue() + "\r\n");
}
// 解析請求引數
QueryStringDecoder queryStringDecoder = new QueryStringDecoder(request.getUri());
Map<String, List<String>> params = queryStringDecoder.getParameters();
if (!params.isEmpty()) {
for (Entry<String, List<String>> p : params.entrySet()) {
String key = p.getKey();
List<String> vals = p.getValue();
for (String val : vals) {
System.out.println("PARAM: " + key + " = " + val + "\r\n");
}
}
}
if (request.isChunked()) {
readingChunks = true;
} else {
ChannelBuffer content = request.getContent();
if (content.readable()) {
System.out.println(content.toString(CharsetUtil.UTF_8));
}
writeResponse(e, uri);
}
} else {// 為分塊編碼時
HttpChunk chunk = (HttpChunk) e.getMessage();
if (chunk.isLast()) {
readingChunks = false;
// END OF CONTENT\r\n"
HttpChunkTrailer trailer = (HttpChunkTrailer) chunk;
if (!trailer.getHeaderNames().isEmpty()) {
for (String name : trailer.getHeaderNames()) {
for (String value : trailer.getHeaders(name)) {
System.out.println("TRAILING HEADER: " + name + " = " + value + "\r\n");
}
}
}
writeResponse(e, "/");
} else {
System.out.println("CHUNK: " + chunk.getContent().toString(CharsetUtil.UTF_8)
+ "\r\n");
}
}
}
private void writeResponse(MessageEvent e, String uri) {
// 解析Connection首部,判斷是否為持久連線
boolean keepAlive = isKeepAlive(request);
// Build the response object.
HttpResponse response = new DefaultHttpResponse(HTTP_1_1, OK);
response.setStatus(HttpResponseStatus.OK);
// 服務端可以通過location首部將客戶端導向某個資源的地址。
// response.addHeader("Location", uri);
if (keepAlive) {
// Add 'Content-Length' header only for a keep-alive connection.
response.setHeader(CONTENT_LENGTH, response.getContent().readableBytes());
}
// 得到客戶端的cookie資訊,並再次寫到客戶端
String cookieString = request.getHeader(COOKIE);
if (cookieString != null) {
CookieDecoder cookieDecoder = new CookieDecoder();
Set<Cookie> cookies = cookieDecoder.decode(cookieString);
if (!cookies.isEmpty()) {
CookieEncoder cookieEncoder = new CookieEncoder(true);
for (Cookie cookie : cookies) {
cookieEncoder.addCookie(cookie);
}
response.addHeader(SET_COOKIE, cookieEncoder.encode());
}
}
final String path = Config.getRealPath(uri);
File localFile = new File(path);
// 如果檔案隱藏或者不存在
if (localFile.isHidden() || !localFile.exists()) {
// 邏輯處理
return;
}
// 如果請求路徑為目錄
if (localFile.isDirectory()) {
// 邏輯處理
return;
}
RandomAccessFile raf = null;
try {
raf = new RandomAccessFile(localFile, "r");
long fileLength = raf.length();
response.setHeader(HttpHeaders.Names.CONTENT_LENGTH, String.valueOf(fileLength));
Channel ch = e.getChannel();
ch.write(response);
// 這裡又要重新溫習下http的方法,head方法與get方法類似,但是伺服器在響應中只返回首部,不會返回實體的主體部分
if (!request.getMethod().equals(HttpMethod.HEAD)) {
ch.write(new ChunkedFile(raf, 0, fileLength, 8192));//8kb
}
} catch (Exception e2) {
e2.printStackTrace();
} finally {
if (keepAlive) {
response.setHeader(CONTENT_LENGTH, response.getContent().readableBytes());
}
if (!keepAlive) {
e.getFuture().addListener(ChannelFutureListener.CLOSE);
}
}
}
private void send100Continue(MessageEvent e) {
HttpResponse response = new DefaultHttpResponse(HTTP_1_1, CONTINUE);
e.getChannel().write(response);
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception {
e.getCause().printStackTrace();
e.getChannel().close();
}
}
4.配置類
public class Config {
public static String getRealPath(String uri) {
StringBuilder sb=new StringBuilder("/home/guolei/workspace/Test/web");
sb.append(uri);
if (!uri.endsWith("/")) {
sb.append('/');
}
return sb.toString();
}
}
5.頁面
在專案中新建一個資料夾,名稱為web(可以在配置中配置),在資料夾中放入靜態頁面index.html。
6.啟動伺服器,測試
相關推薦
網路程式設計知識(5)--用Netty實現的一個簡單的HTTP伺服器
用Netty實現的一個簡單的HTTP伺服器,可以處理靜態檔案,例子中的註釋也比較全。 public class HttpServer { public static void main(String[] args) {
自己用-Netty-實現一個簡單的-RPC
轉自:http://thinkinjava.cn/2018/03/%E8%87%AA%E5%B7%B1%E7%94%A8-Netty-%E5%AE%9E%E7%8E%B0%E4%B8%80%E4%B8%AA%E7%AE%80%E5%8D%95%E7%9A%84-RPC/ 目錄: 需求
Netty學習——用Netty實現一個簡單的Http伺服器
package study.netty; import io.netty.bootstrap.ServerBootstrap; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.C
Windows 上靜態編譯 Libevent 2.0.10 並實現一個簡單 HTTP 伺服器
假設 Visual Studio 2005 的安裝路徑為“D:\Program Files\Microsoft Visual Studio 8\”,Libevent 2.0.10 解壓後的路徑為“D:\libevent-2.0.10-stable”。 編譯生成L
用Numpy實現一個簡單的神經網路
本示例來自於PyTorch的官網上的一個warm-up小示例, 覺得很有代表性, 所有這裡單獨記錄一下. 對於numpy來說, 它對計算圖, 深度學習, 梯度等等概念幾乎是不知道的, 但是, 如果我們瞭
用java實現一個簡單的單用戶登陸功能的思路
get 單用戶 這樣的 簡單的 lock ref 數據庫 清除 一個 引用 所謂“單用戶單賬戶登錄”是指:在同一系統中,一個用戶名不能在兩個地方同時登錄。 我們參照 QQ 實現效果:當某賬號在 A 處登錄後,在未退出的情況下,如果再到 B 處登錄,那麽,系統會擠下 A 處
用 C# 實現一個簡單的 Rest Service 供外部調用
message [] operation rem adk www span method title 用 C# 實現一個簡單的 Restful Service 供外部調用,大體總結為4點: The service contract (the methods it o
用Vue實現一個簡單的輪播效果
Vue實現簡單的輪播效果,用的的一些常用系統指令: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" conte
類方法實現:用python實現一個簡單的單詞本,添加/查找/刪除單詞。
end code div keys style 成功 move print utf 1.實現一個簡單的單詞本,功能: ①添加單詞,當所添加的單詞已存在時,讓用戶知道 ②查找單詞,當查找的單詞不存在時,讓用戶知道 ③刪除單詞,當刪除的單詞不存在時,讓用戶知道 以上
【人工智慧】用Python實現一個簡單的人臉識別,原來我和這個明星如此相似
近幾年來,興起了一股人工智慧熱潮,讓人們見到了AI的能力和強大,比如影象識別,語音識別,機器翻譯,無人駕駛等等。總體來說,AI的門檻還是比較高,不僅要學會使用框架實現,更重要的是,需要有一定的數學基礎,如線性代數,矩陣,微積分等。 幸慶的是,國內外許多大神都已經給我們造好“輪子”,我們可以直接來使用某些模型
【人工智能】用Python實現一個簡單的人臉識別,原來我和這個明星如此相似
數值 但是 智能 深度學習 lib python 數學 三方 python實現 近幾年來,興起了一股人工智能熱潮,讓人們見到了AI的能力和強大,比如圖像識別,語音識別,機器翻譯,無人駕駛等等。總體來說,AI的門檻還是比較高,不僅要學會使用框架實現,更重要的是,需要有一定的數
用js實現一個簡單的mvvm
這裡利用的object.defineproperty() 方法; <input id='input'><p id='p'><p/>js: const data={}; const input=documen
用TextView實現一個簡單的Android資訊顯示工具
本文用 TextView 實現一個在手機上顯示 Android 資訊的工具類。比如涉及到訊號的傳遞時,那種類似日誌記錄的功能。先看圖: 先看佈局檔案的程式碼,注意 TextView 裡面的幾個屬性就可以了。 <?xml version="1.0" encoding="utf-8"
用Python實現一個簡單的——人臉相似度對比
近幾年來,興起了一股人工智慧熱潮,讓人們見到了AI的能力和強大,比如影象識別,語音識別,機器翻譯,無人駕駛等等。總體來說,AI的門檻還是比較高,不僅要學會使用框架實現,更重要的是,需要有一定的數學基礎,如線性代數,矩陣,微積分等。 幸慶的是,國內外許多大神都已經給我們造好“輪子”,我們可以直
【很有趣】用Python實現一個簡單的人臉識別,原來我和這個明星如此相似
近幾年來,興起了一股人工智慧熱潮,讓人們見到了AI的能力和強大,比如影象識別,語音識別,機器翻譯,無人駕駛等等。總體來說,AI的門檻還是比較高,不僅要學會使用框架實現,更重要的是,需要有一定的數學基礎,如線性代數,矩陣,微積分等。 幸慶的是,國內外許多大神都已經給我們造好“輪子”,我們可
用echarts實現一個簡單的生成圖表的功能
說實話一直想做一個可以生成圖表的檔案,但是一直研究不明白,曾經也看過很多的類似技術的檔案,D3.js,Hcharts,Echarts都看過,但是看不下去,一個是api寫的很死板,一個是自己事情比較多,今天不是很忙,簡單的看了一下,寫一個簡單的生成圖表,很簡單,沒有什麼技術含量
用Nodejs實現一個簡單的爬蟲功能。(ES6標準)
Nodejs版本:v10.11.0 依賴模組:express,superagent,cheerio 程式碼: const express = require('express'); const superagent = require('superagent'); co
用mpvue實現一個簡單的demo
序言 上一篇從騰訊後臺搭建以及搭建本地開發環境這兩個方面進行總結。在進行編碼時,這兩種搭建方式也能提供更好的開發環境,提高實際的開發效率。 這一節主要分享的便是如果用mpvue實現一個基礎的demo,這個demo主要會從mpvue的特性、結構,以及生命週期來實現,期間遇到
用java實現一個簡單的ArrayList
重複造輪子雖然不可取,但是溫習一下資料結構,光看不做總是少了什麼,所以也來實現一下List,希望多多包涵。 既然要實現一個List,先來簡單說一下List的定義 線性表是最基本、最簡單、也是最常用的一種資料結構。 線性表中資料元素之間的關係是一對一的關係
用Python3實現一個簡單的爬蟲。
import urllib import urllib.request def loadPage(url,filename): """ 作用:根據url傳送請求,獲取html資料;