netty server

EchoServer

package com.zhaowb.netty.ch5_1;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.DelimiterBasedFrameDecoder;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler; public class EchoServer { public void bind(int port) throws Exception { // 配置 服务端的 NIO 线程组
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup(); try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, 1024)
.handler(new LoggingHandler(LogLevel.INFO))
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ByteBuf delimiter = Unpooled.copiedBuffer("$_".getBytes());// 创建分隔符对象 ByteBuf 使用 $_ 作为分隔符。 // 第一个参数为单条消息的最大长度,当达到该长度后仍然没有查找到分隔符,就抛出 TooLongFrameException 异常
// 防止由于异常码流缺失分隔符导致的内存溢出,这是 netty 解码器的可靠性保护;第二个参数是分隔符缓冲对象。
ch.pipeline().addLast(new DelimiterBasedFrameDecoder(1024, delimiter));
ch.pipeline().addLast(new StringDecoder());
ch.pipeline().addLast(new EchoServerHandler());
}
}); // 绑定端口,同步等待成功。
ChannelFuture f = b.bind(port).sync();
// 等待服务端监听端口关闭。
f.channel().closeFuture().sync();
} catch (Exception e) {
// 退出,释放线程池资源
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
} public static void main(String[] args) throws Exception {
int port = 8080; if (args != null && args.length > 0) {
try {
port = Integer.valueOf(args[0]);
} catch (NumberFormatException e) {
}
}
new EchoServer().bind(port);
}
}

EchoServerHandler

package com.zhaowb.netty.ch5_1;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext; public class EchoServerHandler extends ChannelHandlerAdapter { int counter = 0; @Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
System.out.println("链接成功!");
} @Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { // 当读取信息时,先经过 DelimiterBasedFrameDecoder 去掉结束分隔符,然后再使用 StringDecoder 将 ByteBuf 解码成字符串/
// 然后 EchoServerHandler 收到的数据就是解码后的字符串对象 String body = (String) msg;
System.out.println("This is " + ++counter + " times receive client : [" + body + "]");
body += "$_"; // 由于 设置 DelimiterBasedFrameDecoder 过滤掉了分隔符,返回给客户端时需要在消息的尾部拼接 "$_" ByteBuf echo = Unpooled.copiedBuffer(body.getBytes());
ctx.writeAndFlush(echo);
} @Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();// 发生异常,关闭链路
}
}

netty client

EchoClient

package com.zhaowb.netty.ch5_1;

import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.DelimiterBasedFrameDecoder;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler; public class EchoClient { public void connect(int port, String host) throws Exception { //配置客户端 NIO 线程组
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap b = new Bootstrap();
b.group(group).channel(NioSocketChannel.class)
.option(ChannelOption.TCP_NODELAY, true)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ByteBuf delimiter = Unpooled.copiedBuffer("$_".getBytes());// 创建分隔符对象 ByteBuf 使用 $_ 作为分隔符。
ch.pipeline().addLast(new DelimiterBasedFrameDecoder(1024, delimiter));
ch.pipeline().addLast(new StringDecoder());
ch.pipeline().addLast(new EchoClientHandler());
}
});
// 发起异步连接操作
ChannelFuture f = b.connect(host, port).sync();
// 等待客户端链路关闭
f.channel().closeFuture().sync();
} finally {
// 释放 NIO 线程组
group.shutdownGracefully();
}
} public static void main(String[] args) throws Exception {
int port = 8080;
if (args != null && args.length > 0) {
try {
port = Integer.valueOf(args[0]);
} catch (NumberFormatException e) {
}
}
new EchoClient().connect(port, "127.0.0.1");
}
}

EchoClientHandler

package com.zhaowb.netty.ch5_1;

import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext; public class EchoClientHandler extends ChannelHandlerAdapter { private int counter; static final String ECHO_REQ = "hello.$_"; public EchoClientHandler() {
} @Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
System.out.println("链接成功!");
for (int i = 0; i < 10; i++) {
ctx.writeAndFlush(Unpooled.copiedBuffer(ECHO_REQ.getBytes()));
}
} @Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { System.out.println("This is " + ++counter + "times receive server : [" + msg.toString() + "]");
} @Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
ctx.flush();
} @Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
}

如果sever 没有 ch.pipeline().addLast(new DelimiterBasedFrameDecoder(1024, delimiter));,在接受数据的时候会一起接收到客户端发送的所有数据,造成粘包问题。如果要使用ch.pipeline().addLast(new FixedLengthFrameDecoder(20));就是截取固定长度的信息,超过的不会输出。

https://gitee.com/JiShiMoWang_admin/netty-learning

https://github.com/zhaowenbo1234/netty

最新文章

  1. @RenderSection,@RenderPage,@RenderBody介绍
  2. Java String,StringBuffer和StringBuilder的区别
  3. MVC中视图View向控制器传值的方法
  4. C/C++学习----使用C语言代替cmd命令、cmd命令大全
  5. 微软职位内部推荐-Software Engineer II-SDP
  6. POJ 1160Post Office
  7. Pandas系列教程——写在前面
  8. 吉哥系列故事――临时工计划(dp)
  9. 一个初学所了解的jquery事件
  10. iOS下JS与原生OC互相调用(总结)
  11. JSPWiki安装配置及FCKEditor的集成
  12. Atcoder刷题小记
  13. 【LeetCode-数组篇】 1 Two Sum
  14. virtualenv虚拟环境的使用
  15. ch01 PHP开篇
  16. 【前端技术】web 开发常见问题--GET POST 区别
  17. python 学习笔记之@property
  18. cpp 区块链模拟示例(七) 补充 Merkle树
  19. 【转】python 修改os环境变量
  20. mysql中tinyint、smallint、int、bigint的区别

热门文章

  1. 2019.7.3模拟 光影交错(穷举+概率dp)
  2. bzoj1001题解
  3. linux源码安装python及pip和django
  4. poj1637Sightseeing tour
  5. Feign Request header is too large
  6. NX二次开发-UF_MODL_ask_distance_tolerance获取建模的长度公差
  7. java-day13
  8. 03、request 模块高级
  9. Hive系统架构
  10. JS事件 加载事件(onload)注意:1. 加载页面时,触发onload事件,事件写在&lt;body&gt;标签内。 2. 此节的加载页面,可理解为打开一个新页面时。