前言
构建一个只有Server服务端的netty服务,不需要额外的编写client去访问,也就是说使用现在的软件去访问。 最简单的就是使用浏览器去访问,浏览是HTTP协议,所以服务必须是一个支持HTTP协议的应用。
实现使用: IDEA netty gradle 构建一个简单的HTTP服务,用来学习netty。
主要角色
netty 构建一个服务,需要三个角色参与
- Server 运行服务
- Initializer 组装组件
- Handle 业秋处理
项目构建
可以创建一个gradle
的空项目,这下面的代码复制进到项目中。
build.gradle
复制内容
代码语言:javascript复制//插件管理
plugins {
id 'java'
}
//座标
group 'com.liukai.netty'
version '1.0-SNAPSHOT'
//源和目标编译版本
sourceCompatibility = 1.8
targetCompatibility = 1.8
//仓库,这里使用 maven 远程仓库,也就是说本没有,就去远程获取
repositories {
mavenCentral()
}
//依赖管理
dependencies {
//测试用名,不用打到生产包中
//group是 maven 的 group, name 是 artifactId, version 相同
testCompile group: 'junit', name: 'junit', version: '4.12'
//等价写法,推荐 group:artifactId:version
testCompile(
"junit:junit:4.12"
//多行逗号隔开
)
//编译的包
compile(
"io.netty:netty-all:4.1.10.Final"
//多行逗号隔开
)
}
服务端 NettyServer
代码语言:javascript复制package com.liukai.netty.test01;
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;
/**
* 创建 http 服务器
*
* @author liu kai
* @since 2019-12-29 22:03
*/
public class NettyServer {
public static void main(String[] args) {
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class)
.childHandler(new NettyChannelInitializer());
try {
ChannelFuture channelFuture = bootstrap.bind(8889).sync();
channelFuture.channel().closeFuture().sync();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}
组装组件 NettyChannelInitializer
代码语言:javascript复制package com.liukai.netty.test01;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.http.HttpServerCodec;
/**
* 渠道构建
*
* @author liu kai
* @since 2019-12-29 22:03
*/
public class NettyChannelInitializer extends ChannelInitializer<SocketChannel> {
//这是一个回调的方法,在channel被注册时被调用
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
//这里看一下源码
pipeline.addLast("httpServerCodec", new HttpServerCodec());
//增加一个自己定义的处理器handel
pipeline.addLast("testHttpServerHandler", new NettyServerHandle());
}
}
Handle 业务处理器 NettyServerHandle
代码语言:javascript复制package com.liukai.netty.test01;
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 liu kai
* @since 2019-12-29 22:02
*/
public class NettyServerHandle extends SimpleChannelInboundHandler<HttpObject> {
/**
* 继承InboundHandler类,代表处理进入的请求,还有OutboundHandler,处理出去请求
* 其中里面的泛型表示msg的类型,如果指定了HttpObject,表明这是个HTTP连接的对象
*/
@Override
protected void channelRead0(ChannelHandlerContext ctx, HttpObject msg) throws Exception {
//channelRead0读取客户端请求,并返回响应的方法
//如果不加这个判断使用curl 测试会报错,使用curl测试命令curl "http://localhost:8899"
//判断这个是不是httpRequest请求
if (msg instanceof HttpRequest) {
System.out.println(msg.getClass());
System.out.println(ctx.channel().remoteAddress());
HttpRequest httpRequest = (HttpRequest) msg;
URI uri = new URI(httpRequest.getUri());
ctx.channel().closeFuture();
if ("/favicon.ico".equals(uri.getPath())) {
System.out.println("chrome 请求 favicon");
return;
}
System.out.println("请求方法名: " httpRequest.getMethod().name());
//ByteBuf 是netty中的重要概念,代表响应返回的数据
ByteBuf content = Unpooled.copiedBuffer("Hello World", CharsetUtil.UTF_8);
FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, content);
response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/plain");
response.headers().set(HttpHeaderNames.CONTENT_LENGTH, content.readableBytes());
//如果只是调用write方法,他仅仅是存在缓冲区里,并不会返回客户端
//调用writeAndFlush可以
ctx.writeAndFlush(response);
}
}
}
验证
控制台输出
总结
netty是一个不错的网络通信框架,本身使用起来比较简单,但是越是使用简单的框架底层实现就会比较复杂。 就跟String一样,使用简单,原理复杂是一个样的,但是凡事都是先从会用开始学习。