从零学Netty(六)Netty实现Http服务器
简介
- HTTP协议是Hyper Text Transfer Protocol(超文本传输协议)的缩写
- HTTP是一个基于TCP/IP通信协议来传递数据
工作原理
- HTTP协议工作于C/S架构上,浏览器作为HTTP客户端通过URL向HTTP服务端即WEB服务器发送所有请求
- Web服务器根据接收到的请求后,向客户端发送响应信息
- HTTP默认端口号为80,但是你也可以改为8080或者其他端口
- HTTP是无连接:无连接的含义是限制每次连接只处理一个请求。服务器处理完客户的请求,并收到客户的应答后,即断开连接。采用这种方式可以节省传输时间。
- HTTP是媒体独立的:这意味着,只要客户端和服务器知道如何处理的数据内容,任何类型的数据都可以通过HTTP发送。客户端以及服务器指定使用适合的MIME-type内容类型。
- HTTP是无状态:HTTP协议是无状态协议。无状态是指协议对于事务处理没有记忆能力。缺少状态意味着如果后续处理需要前面的信息,则它必须重传,这样可能导致每次连接传送的数据量增大。另一方面,在服务器不需要先前信息时它的应答就较快。
编写Http Servlet规范类
Servlet抽象类
/**
* Servlet
*
* @author LionLi
*/
public abstract class Servlet {
public abstract void doGet(Request request,Response response);
public abstract void doPost(Request request,Response response);
}
Request相关功能实现
/**
* Request
*
* @author LionLi
*/
public class Request {
private ChannelHandlerContext ctx;
private HttpRequest r;
public Request(ChannelHandlerContext ctx, HttpRequest r) {
this.ctx = ctx;
this.r = r;
}
public String getUri() {
return r.uri();
}
public String getMethod() {
return r.method().name();
}
public Map<String, List<String>> getParameters() {
QueryStringDecoder decoder = new QueryStringDecoder(r.uri());
return decoder.parameters();
}
public String getParameter(String name) {
Map<String, List<String>> params = getParameters();
List<String> param = params.get(name);
if (null == param) {
return null;
} else {
return param.get(0);
}
}
}
Response相关功能实现
/**
* Response
*
* @author LionLi
*/
public class Response {
private ChannelHandlerContext ctx;
private HttpRequest r;
public Response(ChannelHandlerContext ctx, HttpRequest r) {
this.ctx = ctx;
this.r = r;
}
public void write(String out) throws Exception {
try {
if (out == null || out.length() == 0) {
return;
}
// 设置 http协议及请求头信息
FullHttpResponse response = new DefaultFullHttpResponse(
// 设置http版本为1.1
HttpVersion.HTTP_1_1,
// 设置响应状态码
HttpResponseStatus.OK,
// 将输出值写出 编码为UTF-8
Unpooled.wrappedBuffer(out.getBytes("UTF-8")));
// 设置连接类型 为 JSON
response.headers().set(CONTENT_TYPE, "text/json");
// 设置请求头长度
response.headers().set(CONTENT_LANGUAGE, response.content().readableBytes());
// 设置超时时间为5000ms
response.headers().set(EXPIRES, 5000);
// 当前是否支持长连接
// if (HttpUtil.isKeepAlive(r)) {
// // 设置连接内容为长连接
// response.headers().set(CONNECTION, HttpHeaderValues.KEEP_ALIVE);
// }
ctx.write(response);
} finally {
ctx.flush();
ctx.close();
}
}
}
自定义Servlet处理
/**
* servlet处理
*
* @author LionLi
*/
public class MyServlet extends Servlet {
public void doGet(Request request, Response response) {
try {
// 获取 name 参数 并返回
response.write(request.getParameter("name"));
} catch (Exception e) {
e.printStackTrace();
}
}
public void doPost(Request request, Response response) {
doGet(request,response);
}
}
编写Server相关类
http服务器主类
/**
* http服务器
*
* @author LionLi
*/
public class HttpServer {
public void start(int port) throws Exception {
// Boss线程
EventLoopGroup bossGroup = new NioEventLoopGroup();
// Worker线程
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap server = new ServerBootstrap();
server.group(bossGroup, workerGroup)
// 主线程处理类
.channel(NioServerSocketChannel.class)
// 子线程处理类
.childHandler(new ChannelInitializer<SocketChannel>() {
// 客户端初始化处理
protected void initChannel(SocketChannel client) {
// HttpResponseEncoder 编码器
client.pipeline().addLast(new HttpResponseEncoder());
// HttpRequestDecoder 解码器
client.pipeline().addLast(new HttpRequestDecoder());
// 业务逻辑处理
client.pipeline().addLast(new HttpHandler());
}
})
// 针对主线程的配置 分配线程最大数量 128
.option(ChannelOption.SO_BACKLOG, 128)
// 针对子线程的配置 保持长连接
.childOption(ChannelOption.SO_KEEPALIVE, true);
// 启动服务器 sync 同步阻塞
ChannelFuture f = server.bind(port).sync();
System.out.println("HttpServer Startd Port: " + port);
f.channel().closeFuture().sync();
} finally {
// 关闭线程池
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
public static void main(String[] args) {
try {
new HttpServer().start(8088);
} catch (Exception e) {
e.printStackTrace();
}
}
}
业务处理Handler类
/**
* 业务处理
*
* @author LionLi
*/
public class HttpHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
if (msg instanceof HttpRequest){
HttpRequest r = (HttpRequest) msg;
Request request = new Request(ctx,r);
Response response = new Response(ctx,r);
MyServlet.class.newInstance().doGet(request,response);
}
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
}
}
测试
启动HttpServer
启动成功无异常
访问netty服务器 http://localhost:8088/?name=LionLi
成功返回结果
项目已上传到gitee
地址: netty-demo
如果帮到您了,请帮忙点个star
还没有评论,来说两句吧...