HTTP(应用层协议)

默认是80端口,最早推出于1991年

请求/响应

客户端:

HttpResponseDecoder 解码器,处理服务端的响应
HttpRequestEncoder编码器,处理服务端请求

服务端:

HttpRequestDecoder 解码器,处理客户端的请求
HttpResponseEncoder编码器,处理客户端的响应

编解码器

客户端编码解码器HttpClientCodeC:HttpRequestEncoder+HttpResponseDecoder
服务端编码解码器HttpServerCodeC:HttpRequestDecoder+HttpResponseEncoder

压缩

HttpContentCompressor压缩,用于服务端
HttpContentDecompressor解压缩,用于客户端

聚合

由于http的请求和响应,可能由很多部分组成,需要聚合成一个完整的消息
HttpObjectAggregator ->
FullHttpRequest /
FullHttpResponse

发展历程

1) 0.9版本

GET /index.html
服务端只能返回html格式,传输过程只能处理文字

2) 1.0版本

支持任何格式的内容,包括图像、视频、二进制等等
引入了POST命令、HEAD命令
增加了请求头、状态码,以及权限、缓存等
GET / HTTP/1.0
User-Agent:Mozilla/1.0
Accept: */*
HTTP/1.0 200 OK
Content-Type: text/plain
Content-Encoding: gzip
<html><body> hello world </body>
</html>

a、 Content-Type

服务端通知客户端,当前数据的格式
示例: text/html 、 image/png 、 application/pdf 、 video/mp4
前面是一级类型,后面是二级类型,用斜杠分隔; 还可以增加其他参数,如编码格式
Content-Type: text/plain; charset=utf-8

b、Content-Encoding

表示数据压缩的方式,gzip、compress、deflate
对应客户端的字段为 Accept-Encoding,代表接收哪些压缩方式

c、缺点和问题

每个TCP连接只能发送一个请求,发送完毕连接关闭,使用成本很高,性能较差
Connection: keep-alive   - 非标准字段

3) 1.1版本

GET / HTTP/1.1
User-Agent: PostmanRuntime/7.26.8
Accept: */*
Postman-Token: be754386-04ec-4a76-9817-bdd27ddd4b93
Host: cn.bing.com
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
HTTP/1.1 200 OK
Cache-Control: private, max-age=0
Content-Length: 45542
Content-Type: text/html; charset=utf-8
Content-Encoding: br
Vary: Accept-Encoding
P3P: CP="NON UNI COM NAV STA LOC CURa DEVa PSAa PSDa OUR IND"
Set-Cookie: SRCHD=AF=NOFORM; domain=.bing.com; expires=Thu, 15-Dec-2022 08:16:19 GMT; path=/
Set-Cookie: SRCHUID=V=2&GUID=55418C8D9DA04D47B721FCE030EB283B&dmnchg=1; domain=.bing.com; expires=Thu, 15-Dec-2022 08:16:19 GMT; path=/
Set-Cookie: SRCHUSR=DOB=20201215; domain=.bing.com; expires=Thu, 15-Dec-2022 08:16:19 GMT; path=/
Set-Cookie: _SS=SID=1DEB2B301FB66F20330024911EF56EF5; domain=.bing.com; path=/
Set-Cookie: _EDGE_S=F=1&SID=1DEB2B301FB66F20330024911EF56EF5; path=/; httponly; domain=bing.com
Set-Cookie: _EDGE_V=1; path=/; httponly; expires=Sun, 09-Jan-2022 08:16:19 GMT; domain=bing.com
Set-Cookie: MUID=03DC0275D7906F4E3BE10DD4D6D36EAA; samesite=none; path=/; secure; expires=Sun, 09-Jan-2022 08:16:19 GMT; domain=bing.com
Set-Cookie: MUIDB=03DC0275D7906F4E3BE10DD4D6D36EAA; path=/; httponly; expires=Sun, 09-Jan-2022 08:16:19 GMT
X-MSEdge-Ref: Ref A: 835BA58441E44FAAA96A2E12620C9519 Ref B: BJ1EDGE0608 Ref C: 2020-12-15T08:16:19Z
Date: Tue, 15 Dec 2020 08:16:18 GMT
a、持久连接,含义为默认不关闭tcp连接,可以被多个请求复用。大多时候,浏览器对同一个域名,允许同时建立6个连接
b、管道机制,支持客户端发送多个请求,管理请求的顺序的。服务器还是按照接受请求的顺序,返回对应的响应结果
c、Content-Length, 用来区分数据包的重要字段
d、支持PUT、DELETE、PATCH等命令
缺点和问题
当部分请求耗时较长时,仍会阻塞后续请求的处理速度,这种现象叫做“队头阻塞”/“线头阻塞”

4) 2.0版本

解决队头阻塞的问题,使用的是多路复用的方式

代码Demo

public class HttpServer {public static void main(String[] args) {// 可以自定义线程的数量EventLoopGroup bossGroup = new NioEventLoopGroup(1);// 默认创建的线程数量=CPU处理器数量 * 2EventLoopGroup workerGroup = new NioEventLoopGroup();ServerBootstrap serverBootstrap = new ServerBootstrap();serverBootstrap.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class).handler(new LoggingHandler())// 当连接被阻塞时  BACKLOG代表的是 阻塞队列的长度.option(ChannelOption.SO_BACKLOG, 128)// 设置连接为保持活动的状态.childOption(ChannelOption.SO_KEEPALIVE, true).childHandler(new MyHttpInitializer());try {ChannelFuture future = serverBootstrap.bind(9988).sync();future.channel().closeFuture().sync();} catch (InterruptedException e) {e.printStackTrace();} finally {bossGroup.shutdownGracefully();workerGroup.shutdownGracefully();}}
}
public class MyHttpInitializer extends ChannelInitializer<Channel> {@Overrideprotected void initChannel(Channel ch) throws Exception {ChannelPipeline pipeline = ch.pipeline();//先对请求解码,后对响应编码pipeline.addLast("codec", new HttpServerCodec());// 压缩数据pipeline.addLast("compressor", new HttpContentCompressor());// 聚合成完整的消息,参数代表可以处理的最大值(此时是512kb)pipeline.addLast("aggregator", new HttpObjectAggregator(512 * 1024));pipeline.addLast(new MyHttpHandler());}
}
/*** 泛型需要设置为 FullHttpRequest* 筛选msg为此类型的消息才处理*/
public class MyHttpHandler extends SimpleChannelInboundHandler<FullHttpRequest> {@Overrideprotected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest msg) throws Exception {/*** DefaultFullHttpResponse是一个默认的完整http响应* 设定版本号、响应码、响应数据* 设置响应头,HttpHeaders来接收* 设置请求或响应头字段时,可以使用HttpHeaderNames* 设置字段值时,可以使用HttpHeaderValues* 设置包的大小时,调用readableBytes方法*/DefaultFullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1,HttpResponseStatus.OK,Unpooled.wrappedBuffer("This is http netty demo".getBytes()));HttpHeaders headers = response.headers();headers.add(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN + ";charset=UTF-8");headers.add(HttpHeaderNames.CONTENT_LENGTH, response.content().readableBytes());ctx.write(response);}/*** 刷新** @param ctx* @throws Exception*/@Overridepublic void channelReadComplete(ChannelHandlerContext ctx) throws Exception {ctx.flush();
//        super.channelReadComplete(ctx);}
}
运行服务端打开浏览器或者postman 输入ip+端口

WebSocket

websocket是由浏览器发起的
协议标识符 http://127.0.0.1:8080 ws://127.0.0.1:7777
GET ws://127.0.0.1:7777 HTTP/1.1
Host: 127.0.0.1
Upgrade: websocket    # 升级为ws
Connection: Upgrade   # 此链接需要升级
Sec-WebSocket-key: client-random-string ...  # 标识加密相关信息
HTTP/1.1 101
Upgrade: websocket
Connection: Upgrade
响应码 101 代表本次协议需要更改为websocket,连接建立后,支持文本信息及二进制信息

Websocket实现的原理:

http的缺陷:通信只能由客户端发起。因此需要一种服务端能够主动推送的能力—websocket
通过http协议进行连接的建立(握手和回答),建立连接后不再使用http,而tcp自身是支持双向通信的,所以能达到“全双工”的效果
通信使用的单位叫帧 frame

客户端:发送时将消息切割成多个帧

服务端:接收时,将关联的帧重新组装

WebSocket客户端

var ws = new WebSocket("ws://127.0.0.1:7777/hello");
ws.onopen = function(ev){ws.send("hello"); //建立连接后发送数据
}

代码Demo

设计一个样式,左右两个各有一个文本框,中间放一个发送按钮
左侧文本框用来发送数据,右侧文本框用来显示数据
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Hello WebSocket</title>
</head><body><script>var socket;// 判断当前浏览器是否支持websocktif (!window.WebSocket) {alert("不支持websocket")} else {socket = new WebSocket("ws://127.0.0.1:7777/hello");//设置开启连接的方法socket.onopen = function (ev) {var tmp = document.getElementById("respText");tmp.value = "连接已开启";}//设置关闭连接的方法socket.onclose = function (ev) {var tmp = document.getElementById("respText");tmp.value = tmp.value + "\n" + "连接已关闭";}//设置接收数据的方法socket.onmessage = function (ev) {var tmp = document.getElementById("respText");tmp.value = tmp.value + "\n" + ev.data;}}function send(message) {//先判断socket是否已经创建if (!window.socket) {return}//判断socket的状态//CONNECTING正在连接 CLOSING正在关闭//CLOSED已经关闭或打开连接失败//OPEN连接成功可以正常通信if (socket.readyState == WebSocket.OPEN) {socket.send(message);} else {alert("连接未开启");}}</script><!--防止表单自动提交--><form onsubmit="return false"><textarea name="message" style="height: 400px;width: 400px"></textarea><input type="button" value="发送" onclick="send(this.form.message.value)"><textarea id="respText" style="height: 400px;width: 400px"></textarea></form></body>
</html>
public class WebSocketServer {public static void main(String[] args) {//可以自定义线程的数量EventLoopGroup bossGroup = new NioEventLoopGroup(1);//默认创建的线程数量=CPU处理器数量 * 2EventLoopGroup workerGroup = new NioEventLoopGroup();ServerBootstrap serverBootstrap = new ServerBootstrap();serverBootstrap.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class).handler(new LoggingHandler())//当连接被阻塞时BACKLOG代表的是阻塞队列的长度.option(ChannelOption.SO_BACKLOG, 128)//置连接为保持活动的状态.childOption(ChannelOption.SO_KEEPALIVE, true).childHandler(new WebSocketInitializer());try {ChannelFuture future = serverBootstrap.bind(7777).sync();future.channel().closeFuture().sync();} catch (InterruptedException e) {e.printStackTrace();} finally {bossGroup.shutdownGracefully();workerGroup.shutdownGracefully();}}
}
public class WebSocketInitializer extends ChannelInitializer<SocketChannel> {@Overrideprotected void initChannel(SocketChannel ch) throws Exception {ChannelPipeline pipeline = ch.pipeline();//增加编解码器的另一种方式pipeline.addLast(new HttpServerCodec());//块方式写的处理器  用于处理较大数据pipeline.addLast(new ChunkedWriteHandler());//聚合pipeline.addLast(new HttpObjectAggregator(512 * 1024));//声明websocket的请求路径//ws://127.0.0.1:7777/hello//是将http协议升级为websocket协议,并且使用101作为响应码pipeline.addLast(new WebSocketServerProtocolHandler("/hello"));pipeline.addLast(new WebSocketHandler());}
}
/*** 泛型* 代表的是处理数据的单位* TextWebSocketFrame是文本信息帧*/
public class WebSocketHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {@Overrideprotected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws Exception {System.out.println("msg : " + msg.text());Channel channel = ctx.channel();TextWebSocketFrame resp = new TextWebSocketFrame("hello client from websocket server");channel.writeAndFlush(resp);}
}
run 上面那个HTML文件 在打开服务端 刷新


Netty之Http与Websocket相关推荐

  1. 基于Netty最简单的WebSocket通讯

    基于Netty最简单的WebSocket通讯 基于Netty最简单的WebSocket通讯 总览 服务端 EasyWsServer EasyWsServerHandler 客户端 EasyWsClie ...

  2. Springboot实战:Springboot+Netty优雅的创建websocket客户端 (附源码下载)

    Springboot-cli 开发脚手架系列 Netty系列:Springboot+Netty优雅的创建websocket客户端 (附源码下载) 文章目录 Springboot-cli 开发脚手架系列 ...

  3. maven netty 配置_springboot2.3手册:5分钟用Netty搭建高性能异步WebSocket服务

    互联网应用架构:专注编程教学,架构,JAVA,Python,微服务,机器学习等领域,欢迎关注,一起学习. 断更快两个月了,6月份工作忙到飞起,7月份家里又有事,已经累到躺下就想睡觉的程度了. 现在我们 ...

  4. 探讨Netty获取并检查Websocket握手请求的两种方式

    在使用Netty开发Websocket服务时,通常需要解析来自客户端请求的URL.Headers等等相关内容,并做相关检查或处理.本文将讨论两种实现方法. 方法一:基于HandshakeComplet ...

  5. java websocket netty_用SpringBoot集成Netty开发一个基于WebSocket的聊天室

    前言 基于SpringBoot,借助Netty控制长链接,使用WebSocket协议做一个实时的聊天室. 项目效果 项目统一登录路径:http://localhost:8080/chat/netty ...

  6. springboot2.3手册:5分钟用Netty搭建高性能异步WebSocket服务

    溪云阁:专注编程教学,架构,JAVA,Python,微服务,机器学习等领域,欢迎关注,一起学习. 断更快两个月了,6月份工作忙到飞起,7月份家里又有事,已经累到躺下就想睡觉的程度了. 现在我们做Web ...

  7. Netty权威指南之Websocket协议开发

    本章主要学习内容如下: 1.HTTP协议弊端 2.WebSocket入门 3.Netty WebSocket协议开发 第一节:HTTP协议弊端 将HTTP协议的主要弊端总结如下: 1.HTTP协议为半 ...

  8. websocket+netty实时视频弹幕交互功能(Java版)

    欢迎关注方志朋的博客,回复"666"获面试宝典 2021年了,还有不支持弹幕的视频网站吗,现在各种弹幕玩法层出不穷,抽奖,ppt都上弹幕玩法了,不整个弹幕都说不过去了,今天笔者就抽 ...

  9. netty websocket客户端_Websocket操作字节序 之 服务端

    Websocket在JavaScript中操作字节序 之 客户端 在上一篇文章中,把页面的websocket编码写好了,那么服务端又该如何实现呢?由于该文是在上上篇demo中修改的,所以不全的代码还请 ...

最新文章

  1. html5新特性 移除哪些,html5\CSS3有哪些新特性、移除了哪些元素?如何处理HTML5新标签的浏览器兼容问题?如何区分HTML和HTML5?...
  2. 算法-----数组------合并两个有序数组
  3. Hystrix降级逻辑中如何获取触发的异常
  4. Myeclipse的使用方法-添加,修改,删除JRE,修改项目中的jre不显示问题
  5. linux虚拟地址被大量占用,《Linux中为什么要使用虚拟地址》
  6. timeshift备份你的Linux系统
  7. sqlserver创建程序集
  8. Hibernate ,Mybatis 区别,以及各自的一级,二级缓存理解
  9. mysql数据库查询笔记_mysql笔记: 查询
  10. node.js中使用https请求报CERT_UNTRUSTED的问题解决
  11. 教你如何用 Python 三行代码做动图!
  12. iView 实现可编辑表格 1
  13. 23模式之: 迭代器模式demo
  14. Linux 用户授权的方法,linux中用户和权限管理
  15. C语言状态机模块实现
  16. 2.7 汽车之家口碑爬虫
  17. html img 居中填满,html里的img标签怎么居中显示
  18. 速途在线沙龙11期:王通夫唯首次聚首共话SEO
  19. 关于vlc编解码器暂不支持: VLC 无法解码格式“MIDI” (MIDI Audio)解决
  20. 常用的大功率电阻有哪些,电阻功率降额设计要注意什么

热门文章

  1. 嵌入式主板Linux的adb命令adb有线调试使用说明
  2. 快速实战SQL (一) - 检索数据
  3. grep -v grep的作用
  4. 3D视觉——4.手势识别(Gesture Recognition)入门——使用MediaPipe含单帧(Singel Frame)和实时视频(Real-Time Video)
  5. DCT变换(JAVA)
  6. Deep Anomaly Detection with Deviation Networks论文阅读
  7. Hessian矩阵以及在图像中的应用
  8. 人脸识别2:InsightFace实现人脸识别Face Recognition(含源码下载)
  9. 一个AI小白如何理解近似匹配检索
  10. 通俗易懂解释汉明码(附MATLAB实现代码)