学习netty先从最简单的实例开始,三个实体类大概是如下图
首先先创建TestServer实体类
package com.icss.po;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.sctp.nio.NioSctpServerChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
public class TestServer {
public static void main(String[] args) throws Exception{
//事件线程组
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try{
//服务端启动类
ServerBootstrap serverBootstrap = new ServerBootstrap();
//启动服务器
serverBootstrap.group(bossGroup,workerGroup).channel(NioServerSocketChannel.class)//反射方式
.childHandler(new TestServerInitializer());
ChannelFuture channelFuture = serverBootstrap.bind(8899).sync();
//关闭监听
channelFuture.channel().closeFuture().sync();
}
finally {
//关闭
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}
然后创建TestServerInitializer实体类
package com.icss.po;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.http.HttpRequestDecoder;
import io.netty.handler.codec.http.HttpRequestEncoder;
import io.netty.handler.codec.http.HttpServerCodec;
public class TestServerInitializer extends ChannelInitializer<SocketChannel> {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
//HttpServerCodec是HttpRequestDecoder(请求客户端发向给服务端会做一个解码,解码操作是将请求信息提取出来)
// 和HttpRequestEncoder(Http相应的编码服务端向客户端输出响应的时候做相应的编码工作)的组合
pipeline.addLast( "httpServerCodec",new HttpServerCodec());
pipeline.addLast("testHttpServerHandler",new TestHttpServerHandler());
}
}
最后创建TestServerHandler实体类
package com.icss.po;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.*;
import io.netty.util.CharsetUtil;
import java.net.URI;
//SimpleChannelInboundHandler服务器对进来相应的处理
public class TestHttpServerHandler extends SimpleChannelInboundHandler<HttpObject> {
@Override
protected void channelRead0(ChannelHandlerContext ctx, HttpObject msg) throws Exception {
//得到类名
System.out.println(msg.getClass());
//获取远程连接
System.out.println(ctx.channel().remoteAddress());
if (msg instanceof HttpRequest){
//j进行强制类型转换
HttpRequest httpRequest = (HttpRequest)msg;
System.out.println("请求方法名"+httpRequest.method().name());
URI uri = new URI(httpRequest.uri());
if ("favicon.ico".equals(uri.getPath())){
System.out.println("请求favicon.ico");
return;
}
//1、读取客户端发过来的请求,并且向客户端返回相应的方法
ByteBuf content = Unpooled.copiedBuffer("Hello world", CharsetUtil.UTF_8);//返回的内容
//
FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1,
HttpResponseStatus.OK,content);//指定http的协议,状态是200
//设置http协议的头部信息,内容类型只返回字符串
response.headers().set(HttpHeaderNames.CONTENT_TYPE,"text/plain");
//相应类型的长度
response.headers().set(HttpHeaderNames.CONTENT_LENGTH , content.readableBytes());
//2、将相应返回给客户端
// ctx. write()并不会返回给客户端,将信息放在缓冲区中
ctx.writeAndFlush(response);
//判断http是1.0还是1.1 紧着判断等到时间 最后进行关闭
ctx.channel().closeFuture();
}
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
System.out.println("channel active ");
super.channelActive(ctx);
}
@Override
public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
System.out.println("channel register ");
super.channelRegistered(ctx);
}
@Override
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
System.out.println("channel added ");
super.handlerAdded(ctx);
}
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
System.out.println("channel inactive");
super.channelInactive(ctx);
}
@Override
public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
System.out.println("channel unRegister ");
super.channelUnregistered(ctx);
}
}
启动主程序
按住win+R 进入到命令窗口 输入命令telnet localhost 8899
如果显示Talent窗口则说明第一个实例而创建成功
浏览器访问地址http://localhost:8899/
打开调试模式的network或者网络可以看到有两个请求地址
在后台程序加上打印也确确实实请求了两次
如果用telnet去访问确是访问了一次
出现的原因时因为有些网站他们请求图标所以会请求两次
对于http协议来说基于请求和相应式无状态模式,而对于netty底层是ServerSocket不断进行死循环,对于应用层来说,当获取到客户端的请求之后,首先要对http请求进行判断是http1.1还是http1.0,如果是基于http1.1 有一个keep alive时间等待,这个时间一到,服务器端自动的将客户端关闭掉,如果是http1.0 协议是一个短连接的协议请求发送之后,服务器就会把链接关闭掉。