工作中经常用到网络编程,学到这一块就不得不提netty这个框架。下面就写一个helloworld的小demo来记录一下。
引入依赖
<!-- netty -->
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.42.Final</version>
</dependency>
服务器类
package cn.zxw.netty.first;
import io.netty.bootstrap.Bootstrap;
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.socket.nio.NioServerSocketChannel;
import javax.validation.spi.BootstrapState;
/**
* @author zxw
* @version 1.0
* @description netty服务端,基于http的helloWorld
* @data: 2020/3/2 11:21
*/
public class TestServer {
public static void main(String[] args) {
//创建两个事件循环组,boos和worker。boos获取连接,worker是具体工作的。两个内部都是死循环
EventLoopGroup boosGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
//创建服务端启动器,绑定连接和对应的处理器
ServerBootstrap bootstrap = new ServerBootstrap();
//绑定组和添加处理里
bootstrap.group(boosGroup, workerGroup).channel(NioServerSocketChannel.class)
//添加自己定义的处理器
.childHandler(new ServerInit());
//绑定端口连接
ChannelFuture channelFuture = bootstrap.bind(8899).sync();
channelFuture.channel().closeFuture().sync();
} catch (Exception e) {
e.printStackTrace();
} finally {
//优雅关闭
boosGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}
初始化handler类
package cn.zxw.netty.first;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.http.HttpServerCodec;
/**
* @author zxw
* @version 1.0
* @description 添加处理器
* @data: 2020/3/2 11:32
*/
public class ServerInit extends ChannelInitializer<SocketChannel> {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
//获得管道,往管道添加处理器,当连接建立时。会经过这些处理器
ChannelPipeline pipeline = socketChannel.pipeline();
//往管道添加,注意是多例的
pipeline.addLast("httpServerCodec", new HttpServerCodec())
//添加自己的处理器
.addLast("serverHandler", new ServerHandler());
}
}
自定义handle类
package cn.zxw.netty.first;
import com.sun.jndi.toolkit.url.Uri;
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;
/**
* @author zxw
* @version 1.0
* @description 自定义的处理器,连接之后会掉这里的方法
* @data: 2020/3/2 13:48
*/
public class ServerHandler extends SimpleChannelInboundHandler<HttpObject> {
/**
* 读取客户端请求并响应
*
* @param channelHandlerContext 发送响应消息
* @param httpObject 客户端消息
* @throws Exception
*/
@Override
protected void channelRead0(ChannelHandlerContext channelHandlerContext, HttpObject httpObject) throws Exception {
if (httpObject instanceof HttpRequest) {
HttpRequest httpRequest = (HttpRequest) httpObject;
//使用浏览器调用会调用两次
URI uri = new URI(httpRequest.getUri());
if ("/favicon.ico".equals(uri.getPath())) {
System.out.println("请求图标");
return;
}
//设置需要发送的消息
ByteBuf byteBuf = Unpooled.copiedBuffer("HELLO WORLD", CharsetUtil.UTF_8);
//设置响应消息
FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, byteBuf);
//设置头信息
response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/plain");
response.headers().set(HttpHeaderNames.CONTENT_LENGTH, byteBuf.readableBytes());
//发送响应消息
channelHandlerContext.writeAndFlush(response);
// channelHandlerContext.channel().close();
}
}
@Override
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
System.out.println("只要handler有添加就调用");
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
System.out.println("channelActive===执行channelRead0之前执行");
}
@Override
public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
System.out.println("channelRegistered===执行channelRead0之前执行");
}
/* @Override
public void channelRead(ChannelHandlerContext ctx, Object httpObject) throws Exception {
System.out.println("channelRead====和channelRead0一样,如果实现了它就不会再执行channelRead");
}*/
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
System.out.println("channelInactive===如果不进行手动关闭,使用浏览器调用会根据http不同协议的时间来调用");
}
@Override
public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
System.out.println("channelUnregistered==如果不进行手动关闭,使用浏览器调用会根据http不同协议的时间来调用");
}
}