SpringBoot使用netty

Netty是由JBOSS提供的一个java开源框架。java

Netty提供异步的、事件驱动的网络应用程序框架和工具,用以快速开发高性能、高可靠性的网络服务器和客户端程序。算法

也就是说,Netty 是一个基于NIO的客户、服务器端编程框架,使用Netty能够确保你快速和简单的开发出一个网络应用,例如实现了某种协议的客户、服务端应用。spring

Netty至关于简化和流线化了网络应用的编程开发过程,例如:基于TCP和UDP的socket服务开发。编程

“快速”和“简单”并不用产生维护性或性能上的问题。Netty是一个吸取了多种协议(包括FTP、SMTP、HTTP等各类二进制文本协议)的实现经验,并通过至关精心设计的项目。bootstrap

最终,Netty 成功的找到了一种方式,在保证易于开发的同时还保证了其应用的性能,稳定性和伸缩性服务器

本文讲解SpringBoot如何使用Netty服务端和客户端的简单案例以及相关参数解释网络

1、Netty服务端框架

一、导入依赖异步

< dependency>socket

< groupId>org.springframework.boot< /groupId>

< artifactId>spring-boot-starter< /artifactId>

< /dependency>

< dependency>

< groupId>org.projectlombok< /groupId>

< artifactId>lombok< /artifactId>

< /dependency>

< dependency>

< groupId>io.netty< /groupId>

< artifactId>netty-all< /artifactId>

< version>4.1.36.Final< /version>

< /dependency>

二、编写Netty服务端处理器

/**

  • @author Gjing

  • netty服务端处理器 **/ @Slf4j public class NettyServerHandler extends ChannelInboundHandlerAdapter {

/**

  • 客户端链接会触发

*/ @Override public void channelActive(ChannelHandlerContext ctx) throws Exception {

log.info("Channel active......");

}

/** * 客户端发消息会触发

*/ @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {

log.info("服务器收到消息: {}", msg.toString());

ctx.write("你也好哦");

ctx.flush();

}

/**

  • 发生异常触发

*/ @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { cause.printStackTrace(); ctx.close(); } } 三、编写Netty服务端初始化器

/**

  • @author Gjing
  • netty服务初始化器 **/ public class ServerChannelInitializer extends ChannelInitializer { @Override protected void initChannel(SocketChannel socketChannel) throws Exception { //添加编解码 socketChannel.pipeline().addLast("decoder", new StringDecoder(CharsetUtil.UTF_8)); socketChannel.pipeline().addLast("encoder", new StringEncoder(CharsetUtil.UTF_8)); socketChannel.pipeline().addLast(new NettyServerHandler()); } } 四、编写Netty服务启动

/**

  • @author Gjing
  • 服务启动监听器 **/ @Component @Slf4j public class NettyServer {

public void start(InetSocketAddress socketAddress) {

//new 一个主线程组

EventLoopGroup bossGroup = new NioEventLoopGroup(1);

//new 一个工做线程组

EventLoopGroup workGroup = new NioEventLoopGroup(200);

ServerBootstrap bootstrap = new ServerBootstrap()

.group(bossGroup, workGroup)

.channel(NioServerSocketChannel.class)

.childHandler(new ServerChannelInitializer())

.localAddress(socketAddress)

//设置队列大小

.option(ChannelOption.SO_BACKLOG, 1024)

// 两小时内没有数据的通讯时,TCP会自动发送一个活动探测数据报文

.childOption(ChannelOption.SO_KEEPALIVE, true);

//绑定端口,开始接收进来的链接

try {

ChannelFuture future = bootstrap.bind(socketAddress).sync();

log.info("服务器启动开始监听端口: {}", socketAddress.getPort());

future.channel().closeFuture().sync();

} catch (InterruptedException e) {

e.printStackTrace();

} finally {

//关闭主线程组

bossGroup.shutdownGracefully();

//关闭工做线程组

workGroup.shutdownGracefully();

}

} }

五、启动类

@SpringBootApplication

public class ServerApplication {

public static void main(String[] args) {

SpringApplication.run(ServerApplication.class, args) ; //启动服务端

NettyServer nettyServer = new NettyServer();

nettyServer.start(new InetSocketAddress("127.0.0.1", 8090));

}

} 六、启动结果

2、Netty客户端 一、添加依赖

< dependency>

< groupId>org.springframework.boot< /groupId>

< artifactId>spring-boot-starter< /artifactId>

< /dependency>

< dependency>

< groupId>org.projectlombok< /groupId>

< artifactId>lombok< /artifactId>

< /dependency>

< dependency>

< groupId>io.netty< /groupId>

< artifactId>netty-all< /artifactId>

< version>4.1.36.Final< /version>

< /dependency>

二、编写客户端处理器

/**

  • @author Gjing
  • 客户端处理器 **/ @Slf4j

public class NettyClientHandler extends ChannelInboundHandlerAdapter {

@Override

public void channelActive(ChannelHandlerContext ctx) throws Exception {

log.info("客户端Active .....");

}

@Override

public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {

log.info("客户端收到消息: {}", msg.toString());

}

@Override

public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {

cause.printStackTrace();

ctx.close();

}

}

三、编写客户端初始化器

/**

  • @author Gjing

  • 客户端初始化器

**/ public class NettyClientInitializer extends ChannelInitializer {

@Override

protected void initChannel(SocketChannel socketChannel) throws Exception {

socketChannel.pipeline().addLast("decoder", new StringDecoder());

socketChannel.pipeline().addLast("encoder", new StringEncoder());

socketChannel.pipeline().addLast(new NettyClientHandler());

}

}

四、编写客户端

/**

  • @author Gjing

**/ @Component

@Slf4j

public class NettyClient {

public void start() {

EventLoopGroup group = new NioEventLoopGroup();

Bootstrap bootstrap = new Bootstrap()

.group(group)

//该参数的做用就是禁止使用Nagle算法,使用于小数据即时传输

.option(ChannelOption.TCP_NODELAY, true)

.channel(NioSocketChannel.class)

.handler(new NettyClientInitializer());

try {

ChannelFuture future = bootstrap.connect("127.0.0.1", 8090).sync();

log.info("客户端成功....");

//发送消息

future.channel().writeAndFlush("你好啊");

// 等待链接被关闭

future.channel().closeFuture().sync();

} catch (InterruptedException e) {

e.printStackTrace();

}finally {

group.shutdownGracefully();

}

}

}

五、启动类

@SpringBootApplication

public class ClientApplication {

public static void main(String[] args) {

SpringApplication.run(ClientApplication.class, args);

//启动netty客户端

NettyClient nettyClient = new NettyClient();

nettyClient.start();

}

} 六、启动结果

客户端

服务端

3、ChannelOption参数详解 一、ChannelOption.SO_BACKLOG

ChannelOption.SO_BACKLOG对应的是tcp/ip协议listen函数中的backlog参数,函数listen(int socketfd,int backlog)用来初始化服务端可链接队列,服务端处理客户端链接请求是顺序处理的,因此同一时间只能处理一个客户端链接,多个客户端来的时候,服务端将不能处理的客户端链接请求放在队列中等待处理,backlog参数指定了队列的大小

二、ChannelOption.SO_REUSEADDR

ChanneOption.SO_REUSEADDR对应于套接字选项中的SO_REUSEADDR,这个参数表示容许重复使用本地地址和端口,好比,某个服务器进程占用了TCP的80端口进行监听,此时再次监听该端口就会返回错误,使用该参数就能够解决问题,该参数容许共用该端口,这个在服务器程序中比较常使用,好比某个进程非正常退出,该程序占用的端口可能要被占用一段时间才能容许其余进程使用,并且程序死掉之后,内核一须要必定的时间才可以释放此端口,不设置SO_REUSEADDR就没法正常使用该端口。

三、ChannelOption.SO_KEEPALIVE

Channeloption.SO_KEEPALIVE参数对应于套接字选项中的SO_KEEPALIVE,该参数用于设置TCP链接,当设置该选项之后,链接会测试连接的状态,这个选项用于可能长时间没有数据交流的链接。当设置该选项之后,若是在两小时内没有数据的通讯时,TCP会自动发送一个活动探测数据报文

四、ChannelOption.SO_SNDBUF和ChannelOption.SO_RCVBUF

ChannelOption.SO_SNDBUF参数对应于套接字选项中的SO_SNDBUF,ChannelOption.SO_RCVBUF参数对应于套接字选项中的SO_RCVBUF这两个参数用于操做接收缓冲区和发送缓冲区的大小,接收缓冲区用于保存网络协议站内收到的数据,直到应用程序读取成功,发送缓冲区用于保存发送数据,直到发送成功。

五、ChannelOption.SO_LINGER

ChannelOption.SO_LINGER参数对应于套接字选项中的SO_LINGER,Linux内核默认的处理方式是当用户调用close()方法的时候,函数返回,在可能的状况下,尽可能发送数据,不必定保证会发生剩余的数据,形成了数据的不肯定性,使用SO_LINGER能够阻塞close()的调用时间,直到数据彻底发送

六、ChannelOption.TCP_NODELAY

ChannelOption.TCP_NODELAY参数对应于套接字选项中的TCP_NODELAY,该参数的使用与Nagle算法有关,Nagle算法是将小的数据包组装为更大的帧而后进行发送,而不是输入一次发送一次,所以在数据包不足的时候会等待其余数据的到了,组装成大的数据包进行发送,虽然该方式有效提升网络的有效负载,可是却形成了延时,而该参数的做用就是禁止使用Nagle算法,使用于小数据即时传输,于TCP_NODELAY相对应的是TCP_CORK,该选项是须要等到发送的数据量最大的时候,一次性发送数据,适用于文件传输。

七、IP_TOS

IP参数,设置IP头部的Type-of-Service字段,用于描述IP包的优先级和QoS选项。

八、ALLOW_HALF_CLOSURE

Netty参数,一个链接的远端关闭时本地端是否关闭,默认值为False。值为False时,链接自动关闭;为True时,触发ChannelInboundHandler的userEventTriggered()方法,事件为ChannelInputShutdownEvent。

4、Netty的future.channel().closeFuture().sync();到底有什么用?

主线程执行到这里就 wait 子线程结束,子线程才是真正监听和接受请求的,closeFuture()是开启了一个channel的监听器,负责监听channel是否关闭的状态,若是监听到channel关闭了,子线程才会释放,syncUninterruptibly()让主线程同步等待子线程结果

相关文章
相关标签/搜索