Netty实现客户端和服务端通信简单例子
Netty是建立在NIO基础之上,Netty在NIO之上又提供了更高层次的抽象。
在Netty里面,Accept连接可以使用单独的线程池去处理,读写操作又是另外的线程池来处理。
Accept连接和读写操作也可以使用同一个线程池来进行处理。而请求处理逻辑既可以使用单独的线程池进行处理,也可以跟放在读写线程一块处理。线程池中的每一个线程都是NIO线程。用户可以根据实际情况进行组装,构造出满足系统需求的并发模型。
Netty提供了内置的常用编解码器,包括行编解码器[一行一个请求],前缀长度编解码器[前N个字节定义请求的字节长度],可重放解码器[记录半包消息的状态],HTTP编解码器,WebSocket消息编解码器等等
Netty提供了一些列生命周期回调接口,当一个完整的请求到达时,当一个连接关闭时,当一个连接建立时,用户都会收到回调事件,然后进行逻辑处理。
Netty可以同时管理多个端口,可以使用NIO客户端模型,这些对于RPC服务是很有必要的。
Netty除了可以处理TCP Socket之外,还可以处理UDP Socket。
在消息读写过程中,需要大量使用ByteBuffer,Netty对ByteBuffer在性能和使用的便捷性上都进行了优化和抽象。
代码:
服务端:
package com.kinson.netty.server; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.Channel; import io.netty.channel.ChannelOption; import io.netty.channel.EventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.nio.NioServerSocketChannel; /** * descripiton:服务端 * * @author: www.iknowba.cn * @date: 2018/3/23 * @time: 15:37 * @modifier: * @since: */ public class NettyServer { /** * 端口 */ private int port; public NettyServer(int port) { this.port = port; } public void run() { //EventLoopGroup是用来处理IO操作的多线程事件循环器 //负责接收客户端连接线程 EventLoopGroup bossGroup = new NioEventLoopGroup(); //负责处理客户端i/o事件、task任务、监听任务组 EventLoopGroup workerGroup = new NioEventLoopGroup(); //启动 NIO 服务的辅助启动类 ServerBootstrap bootstrap = new ServerBootstrap(); bootstrap.group(bossGroup, workerGroup); //配置 Channel bootstrap.channel(NioServerSocketChannel.class); bootstrap.childHandler(new ServerIniterHandler()); //BACKLOG用于构造服务端套接字ServerSocket对象, // 标识当服务器请求处理线程全满时,用于临时存放已完成三次握手的请求的队列的最大长度 bootstrap.option(ChannelOption.SO_BACKLOG, 1024); //是否启用心跳保活机制 bootstrap.childOption(ChannelOption.SO_KEEPALIVE, true); try { //绑定服务端口监听 Channel channel = bootstrap.bind(port).sync().channel(); System.out.println("server run in port " + port); //服务器关闭监听 /*channel.closeFuture().sync()实际是如何工作: channel.closeFuture()不做任何操作,只是简单的返回channel对象中的closeFuture对象,对于每个Channel对象,都会有唯一的一个CloseFuture,用来表示关闭的Future, 所有执行channel.closeFuture().sync()就是执行的CloseFuturn的sync方法,从上面的解释可以知道,这步是会将当前线程阻塞在CloseFuture上*/ channel.closeFuture().sync(); } catch (InterruptedException e) { e.printStackTrace(); } finally { //关闭事件流组 bossGroup.shutdownGracefully(); workerGroup.shutdownGracefully(); } } public static void main(String[] args) { new NettyServer(8899).run(); } }
服务端业务逻辑处理:
package com.kinson.netty.server; import io.netty.channel.Channel; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.SimpleChannelInboundHandler; import io.netty.channel.group.ChannelGroup; import io.netty.channel.group.DefaultChannelGroup; import io.netty.util.concurrent.GlobalEventExecutor; /** * descripiton: 服务器的处理逻辑 * * @author: www.iknowba.cn * @date: 2018/3/23 * @time: 15:50 * @modifier: * @since: */ public class ServerHandler extends SimpleChannelInboundHandler<String> { /** * 所有的活动用户 */ public static final ChannelGroup group = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE); /** * 读取消息通道 * * @param context * @param s * @throws Exception */ @Override protected void channelRead0(ChannelHandlerContext context, String s) throws Exception { Channel channel = context.channel(); //当有用户发送消息的时候,对其他的用户发送消息 for (Channel ch : group) { if (ch == channel) { ch.writeAndFlush("[you]: " + s + "\n"); } else { ch.writeAndFlush("[" + channel.remoteAddress() + "]: " + s + "\n"); } } System.out.println("[" + channel.remoteAddress() + "]: " + s + "\n"); } /** * 处理新加的消息通道 * * @param ctx * @throws Exception */ @Override public void handlerAdded(ChannelHandlerContext ctx) throws Exception { Channel channel = ctx.channel(); for (Channel ch : group) { if (ch == channel) { ch.writeAndFlush("[" + channel.remoteAddress() + "] coming"); } } group.add(channel); } /** * 处理退出消息通道 * * @param ctx * @throws Exception */ @Override public void handlerRemoved(ChannelHandlerContext ctx) throws Exception { Channel channel = ctx.channel(); for (Channel ch : group) { if (ch == channel) { ch.writeAndFlush("[" + channel.remoteAddress() + "] leaving"); } } group.remove(channel); } /** * 在建立连接时发送消息 * * @param ctx * @throws Exception */ @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { Channel channel = ctx.channel(); boolean active = channel.isActive(); if (active) { System.out.println("[" + channel.remoteAddress() + "] is online"); } else { System.out.println("[" + channel.remoteAddress() + "] is offline"); } ctx.writeAndFlush("[server]: welcome"); } /** * 退出时发送消息 * * @param ctx * @throws Exception */ @Override public void channelInactive(ChannelHandlerContext ctx) throws Exception { Channel channel = ctx.channel(); if (!channel.isActive()) { System.out.println("[" + channel.remoteAddress() + "] is offline"); } else { System.out.println("[" + channel.remoteAddress() + "] is online"); } } /** * 异常捕获 * * @param ctx * @param e * @throws Exception */ @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable e) throws Exception { Channel channel = ctx.channel(); System.out.println("[" + channel.remoteAddress() + "] leave the room"); ctx.close().sync(); } }
服务端处理器注册:
package com.kinson.netty.server; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelPipeline; import io.netty.channel.socket.SocketChannel; import io.netty.handler.codec.string.StringDecoder; import io.netty.handler.codec.string.StringEncoder; /** * descripiton: 服务器初始化 * * @author: www.iknowba.cn * @date: 2018/3/23 * @time: 15:46 * @modifier: * @since: */ public class ServerIniterHandler extends ChannelInitializer<SocketChannel> { @Override protected void initChannel(SocketChannel socketChannel) throws Exception { //管道注册handler ChannelPipeline pipeline = socketChannel.pipeline(); //编码通道处理 pipeline.addLast("decode", new StringDecoder()); //转码通道处理 pipeline.addLast("encode", new StringEncoder()); //聊天服务通道处理 pipeline.addLast("chat", new ServerHandler()); } }
客户端:
package com.kinson.netty.client; import io.netty.bootstrap.Bootstrap; import io.netty.channel.Channel; import io.netty.channel.EventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.nio.NioSocketChannel; import org.apache.commons.lang3.StringUtils; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; /** * descripiton: 客户端 * * @author: www.iknowba.cn * @date: 2018/3/23 * @time: 16:40 * @modifier: * @since: */ public class NettyClient { private String ip; private int port; private boolean stop = false; public NettyClient(String ip, int port) { this.ip = ip; this.port = port; } public void run() throws IOException { //设置一个多线程循环器 EventLoopGroup workerGroup = new NioEventLoopGroup(); //启动附注类 Bootstrap bootstrap = new Bootstrap(); bootstrap.group(workerGroup); //指定所使用的NIO传输channel bootstrap.channel(NioSocketChannel.class); //指定客户端初始化处理 bootstrap.handler(new ClientIniterHandler()); try { //连接服务 Channel channel = bootstrap.connect(ip, port).sync().channel(); while (true) { //向服务端发送内容 BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); String content = reader.readLine(); if (StringUtils.isNotEmpty(content)) { if (StringUtils.equalsIgnoreCase(content, "q")) { System.exit(1); } channel.writeAndFlush(content); } } } catch (InterruptedException e) { e.printStackTrace(); System.exit(1); } finally { workerGroup.shutdownGracefully(); } } public static void main(String[] args) throws Exception { new NettyClient("127.0.0.1", 8899).run(); } }
客户端逻辑处理:
package com.kinson.netty.client; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.SimpleChannelInboundHandler; /** * descripiton: 客户端逻辑处理 * * @author: www.iknowba.cn * @date: 2018/3/23 * @time: 16:50 * @modifier: * @since: */ public class ClientHandler extends SimpleChannelInboundHandler<String> { @Override protected void channelRead0(ChannelHandlerContext ctx, String s) throws Exception { //打印服务端的发送数据 System.out.println(s); } }
客户端处理器注册:
package com.kinson.netty.client; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelPipeline; import io.netty.channel.socket.SocketChannel; import io.netty.handler.codec.http.HttpClientCodec; import io.netty.handler.codec.string.StringDecoder; import io.netty.handler.codec.string.StringEncoder; /** * descripiton: 客户端处理初始化 * * @author: www.iknowba.cn * @date: 2018/3/23 * @time: 16:55 * @modifier: * @since: */ public class ClientIniterHandler extends ChannelInitializer<SocketChannel> { @Override protected void initChannel(SocketChannel socketChannel) throws Exception { //注册管道 ChannelPipeline pipeline = socketChannel.pipeline(); pipeline.addLast("decoder", new StringDecoder()); pipeline.addLast("encoder", new StringEncoder()); pipeline.addLast("http", new HttpClientCodec()); pipeline.addLast("chat", new ClientHandler()); } }
测试时先启动服务端,再启动客户端。。。
Netty实现客户端和服务端通信简单例子的更多相关文章
- Netty入门——客户端与服务端通信
Netty简介Netty是一个基于JAVA NIO 类库的异步通信框架,它的架构特点是:异步非阻塞.基于事件驱动.高性能.高可靠性和高可定制性.换句话说,Netty是一个NIO框架,使用它可以简单快速 ...
- WCF客户端与服务端通信简单入门教程
服务端 1.新建空白解决方案,然后再空白解决方案中新建:WCF服务应用程序.建完后如图: 2.删掉自动生成的IService1.cs和Service.svc并添加WCF服务文件StudentServi ...
- netty-3.客户端与服务端通信
(原) 第三篇,客户端与服务端通信 以下例子逻辑: 如果客户端连上服务端,服务端控制台就显示,XXX个客户端地址连接上线. 第一个客户端连接成功后,客户端控制台不显示信息,再有其它客户端再连接上线,则 ...
- Netty入门之客户端与服务端通信(二)
Netty入门之客户端与服务端通信(二) 一.简介 在上一篇博文中笔者写了关于Netty入门级的Hello World程序.书接上回,本博文是关于客户端与服务端的通信,感觉也没什么好说的了,直接上代码 ...
- Python进阶----SOCKET套接字基础, 客户端与服务端通信, 执行远端命令.
Python进阶----SOCKET套接字基础, 客户端与服务端通信, 执行远端命令. 一丶socket套接字 什么是socket套接字: 专业理解: socket是应用层与TCP/IP ...
- Android BLE与终端通信(三)——客户端与服务端通信过程以及实现数据通信
Android BLE与终端通信(三)--客户端与服务端通信过程以及实现数据通信 前面的终究只是小知识点,上不了台面,也只能算是起到一个科普的作用,而同步到实际的开发上去,今天就来延续前两篇实现蓝牙主 ...
- 基于开源SuperSocket实现客户端和服务端通信项目实战
一.课程介绍 本期带给大家分享的是基于SuperSocket的项目实战,阿笨在实际工作中遇到的真实业务场景,请跟随阿笨的视角去如何实现打通B/S与C/S网络通讯,如果您对本期的<基于开源Supe ...
- Python socket编程客户端与服务端通信
[本文出自天外归云的博客园] 目标:实现客户端与服务端的socket通信,消息传输. 客户端 客户端代码: from socket import socket,AF_INET,SOCK_STREAM ...
- 实验09——java基于TCP实现客户端与服务端通信
TCP通信 需要先创建连接 - 并且在创建连接的过程中 需要经过三次握手 底层通过 流 发送数据 数据没有大小限制 可靠的传输机制 - 丢包重发 包的顺序的 ...
随机推荐
- Web/app端自动化测试对比
Web/app端自动化测试 做了一段时间的Android自动化测试,对比个人之前做的web端自动化测试,有一些感想.(由于个人接触的时间也不是太久,很多东西理解也并不深刻,先写下菜鸟时期的感想.) 区 ...
- Java 多线程入门
进程与线程 在学习Java多线程之前,先简单复习一下进程与线程的知识. 进程:进程是系统进行资源分配和调度的基本单位,可以将进程理解为一个正在执行的程序,比如一款游戏. 线程:线程是程序执行的最小单位 ...
- Fabric单节点安装备忘
安装文档:http://www.cnblogs.com/studyzy/p/7437157.html 安装上面的文档安装成功,但是过程中遇到一些问题. 一.go的源码包可能下载不下来,因为被墙,go官 ...
- Storm业务功能
监控平台当前使用storm对日志进行流式分析计算,用于支撑监控数据清洗,后来逐渐在storm上搭建起数据在线关联,数据离线关联,明细数据清洗,日志搜索等功能,本章节对各功能进行简要概述. 对storm ...
- js获取文本的行数
<div class="txt" style="line-height:30px">我是文字<br>我是文字<br>我是文字 ...
- R语言实现关联规则与推荐算法(学习笔记)
R语言实现关联规则 笔者前言:以前在网上遇到很多很好的关联规则的案例,最近看到一个更好的,于是便学习一下,写个学习笔记. 1 1 0 0 2 1 1 0 0 3 1 1 0 1 4 0 0 0 0 5 ...
- Solution for link error:Cannot Open File 'python27_d.lib'
引自:http://guangboo.org/2013/01/17/solution-link-errorcannot-open-file-python27_dlib 感谢原作者 使用C调用Pytho ...
- Html细线表格的实现 打印边框设置
在网页制作中,我们常常会使用到表格,表格使得需要表达的信息更清楚,明了. <table border="1" cellspacing="0" border ...
- 主流nosql数据库对比
目前开源的NOSQL数据库有,Redis,Tokyo Cabinet,Cassandra,Voldemort,MongoDB,Dynomite,HBase,CouchDB,Hypertable, Ri ...
- 简述“类(class)”,“类库(class library)”,“包(package)”,“jar文件”这四个概念间的关系
(1)类(class)实际上是对某种类型的对象定义变量和方法的原型,它表示对现实生活中的一类具有共同特征的事物的抽象. (2)为了更好地组织类,java提供了包机制.包(package)是类的容器,用 ...