netty的聊天demo
来源:互联网 发布:夏达 抄袭 知乎 编辑:程序博客网 时间:2024/05/06 02:22
netty是一个基于nio的通讯框架,如果想要看懂netty那么就先要对nio有一定了解,但这篇文章并不讨论nio。 传统的socket通信的话一个线程只能应对一个客户端,但是nio技术中就可以在一条线程开启多个channel通道应对多个客户端,从而降低服务端的压力。 直接上代码:
public class Server { private int port; public Server(int port) { this.port = port; } public void run() throws Exception { //创建两个EventLoopGroup对象,boss用于接收所有进来的连接然后下发给worker。 // 而worker是用于专门对这个客户端进行服务,有多少个客户端就有多少worker。 EventLoopGroup bossGroup = new NioEventLoopGroup(); EventLoopGroup workerGroup = new NioEventLoopGroup(); try { //创建一个server端引导项进行各项属性的设置。 ServerBootstrap b = new ServerBootstrap(); b.group(bossGroup, workerGroup); b.channel(NioServerSocketChannel.class); b.childHandler(new ServerInitializer()); b.option(ChannelOption.SO_BACKLOG, 128); b.childOption(ChannelOption.SO_KEEPALIVE, true); System.out.println("server 启动"); // 同步绑定端口,开始接收进来的连接 ChannelFuture f = b.bind(port).sync(); // 同步等待服务器 socket 关闭 。 f.channel().closeFuture().sync(); } finally { workerGroup.shutdownGracefully(); bossGroup.shutdownGracefully(); System.out.println("server关闭了"); } } public static void main(String[] args) throws Exception { new Server(16666).run(); }}
netty的server端的大体完成了,但还需要一个ChannelInitializer以及SimpleChannelInboundHandler。
public class ServerInitializer extends ChannelInitializer<SocketChannel> { @Override public void initChannel(SocketChannel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); /** * 分割器,遇到换行符则进行分隔并对这个1024字节数据进行处理。这可以用于解决黏包问题,当然更高级的黏包解决方案就需要自己开动脑筋了。 * 但如果你的客户端并不发送带有\n换行符,那么就有可能客户端一直发送消息但你就是没能及时处理 * 导致buffer被写满抛出tooLongFrameLength异常。 */ pipeline.addLast("framer", new DelimiterBasedFrameDecoder(1024, Delimiters.lineDelimiter())); /** * 解码器,如果你的项目是要接收字节数组这种数据的话就不需要StringEncoder,否则它就会将接收到的数据进行默认环境下编码成字符串; */ pipeline.addLast("decoder", new StringDecoder()); /** * 编码器,将你要发送给客户端的数据编码为字符串。 */ pipeline.addLast("encoder", new StringEncoder()); /** * handler */ pipeline.addLast("handler", new ServerHandler()); System.out.println("客户端:" + ch.remoteAddress() + "连接上"); }}
public class ServerHandler extends SimpleChannelInboundHandler<String> { //创建一个全局的channelGroup以方便调用。 public static ChannelGroup channels = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE); @Override public void handlerAdded(ChannelHandlerContext ctx) throws Exception { Channel incoming = ctx.channel(); channels.writeAndFlush(incoming.remoteAddress() + " 加入\n"); //将连接上的channel添加进Group中去,以便调用 channels.add(ctx.channel()); } /** * 客户端close时调用该方法。 * * @param ctx * @throws Exception */ @Override public void handlerRemoved(ChannelHandlerContext ctx) throws Exception { Channel incoming = ctx.channel(); channels.writeAndFlush(incoming.remoteAddress() + " 离开\n"); } /** * 读取内容。 * * @param ctx * @param s * @throws Exception */ @Override protected void channelRead0(ChannelHandlerContext ctx, String s) throws Exception { Channel incoming = ctx.channel(); for (Channel channel : channels) { if (channel != incoming) { //向客户端写入数据 channel.writeAndFlush("服务端已收到\n"); System.out.println("客户端说:" + s); } else { //向客户端写入数据 channel.writeAndFlush("服务端已收到\n"); System.out.println("客户端说:" + s); } } } /** * 检测是否在线方法。 * * @param ctx * @throws Exception */ @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { Channel incoming = ctx.channel(); System.out.println("客户端:" + incoming.remoteAddress() + "在线"); } /** * 客户端掉线时调用该方法 * * @param ctx * @throws Exception */ @Override public void channelInactive(ChannelHandlerContext ctx) throws Exception { Channel incoming = ctx.channel(); System.out.println("客户端:" + incoming.remoteAddress() + "掉线"); } /** * 该channel发生异常时调用的方法, * * @param ctx * @param cause */ @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { Channel incoming = ctx.channel(); System.out.println("客户端:" + incoming.remoteAddress() + "异常"); // 当出现异常就关闭连接 cause.printStackTrace(); ctx.close(); }}
------------------分割线---------------
接下来的是客户端代码:
public class Client { public static void main(String[] args) throws Exception{ new Client("localhost", 16666).run(); } private final String host; private final int port; public Client(String host, int port){ this.host = host; this.port = port; } public void run() throws Exception{ EventLoopGroup group = new NioEventLoopGroup(); try { //创建一个引导项,设置各种属性项 Bootstrap bootstrap = new Bootstrap() .group(group) .channel(NioSocketChannel.class) .handler(new ClientInitializer()); //同步连接到服务端 Channel channel = bootstrap.connect(host, port).sync().channel(); //读取控制台的信息。 BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); while(true){ //channel向服务端发送讯息。 channel.writeAndFlush(in.readLine() + "\r\n"); } } catch (Exception e) { e.printStackTrace(); } finally { group.shutdownGracefully(); } }}
public class ClientInitializer extends ChannelInitializer<SocketChannel> { @Override public void initChannel(SocketChannel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); pipeline.addLast("framer", new DelimiterBasedFrameDecoder(1024, Delimiters.lineDelimiter())); pipeline.addLast("decoder", new StringDecoder()); pipeline.addLast("encoder", new StringEncoder()); pipeline.addLast("handler", new ClientHandler()); }}
public class ClientHandler extends SimpleChannelInboundHandler<String> { @Override protected void channelRead0(ChannelHandlerContext ctx, String s) throws Exception { System.out.println(s); }}
一个Netty的基本通讯demo就完成了。
0 0
- netty的聊天demo
- 一个基于netty的websocket聊天demo
- netty学习三:基于socket的聊天小demo
- 基于Netty的文件上传下载、心跳检测、在线聊天的demo
- 简单的netty demo
- protobuf+netty的demo
- Netty的websocket Demo
- netty demo
- 基于netty的时间服务器demo
- Android聊天的界面的小DEMO
- Netty 实现聊天功能
- Netty 实现聊天功能
- Netty 实现聊天功能
- netty聊天架构
- Netty 实现聊天功能
- netty 点对点聊天程序
- Netty 实现聊天功能
- Netty 实现聊天功能
- C++的流程控制语句
- 文章标题
- yii2 利用dropDownList组件实现三级联动
- PAT--1097. Deduplication on a Linked List
- leetcode(86).387. First Unique Character in a String
- netty的聊天demo
- 定时器
- DOS 命令大全
- Spark2.0.1 on yarn with hue 集群安装部署(九)启动脚本编写
- 用一道例题来分享两种匹配字符串的算法!
- 蒙特卡洛法求圆周率
- 文章标题
- Linux学习笔记——Linux文件权限
- Mycat之——配置文件server.xml