文档章节

Netty进阶篇之简单版websocket发消息(7)

木九天
 木九天
发布于 07/23 21:34
字数 1208
阅读 18
收藏 0

序言:简单开发前端发送消息,后端接收消息并返回。

1、故事牵引

今天通过一个故事来讲解netty,主要讲client和server端和下面的主要实现类。

客户要去ktv唱歌,进入ktv之前,门口会有招待服务生,然后招待服务生看到客户之后,会安排你们给ktv内部服务生给你们安排房间,然后带你们进入ktv房间唱歌,准备开始唱歌就要打开音乐,选好歌曲,打开灯光等因素,之后这个期间你们可能会让唱歌的服务生来助唱,让会跳舞的服务生给你们跳舞,甚至让服务生带来酒或者吃的,直到你们唱歌结束付完钱离开为止,整个过程就算结束。

专有名词解释:

client端:客户

server端:ktv

mainGroup或者boosGroup:主线程组,相当于ktv门口外的招待服务生

subGroup或者workerGroup:子线程组,相当于ktv内部服务生,负责安排房间的,由招待服务生通知内部服务生安排给他们的

ServerBootstrap :客户进入ktv之前到离开ktv之后的整个流程

HelloServerInitializer:进入ktv房间之后的整个流程

CustomHandler :分别代表唱歌服务生、端茶送水服务生、跳舞服务生各个实现的功能等等

1、NIO图

2、server端

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;

/**
 * @Description: 实现客户端发送一个请求,服务器会返回 hello netty
 */
public class HelloServer {

   public static void main(String[] args) throws Exception {

      // 定义一对线程组
      // 主线程组, 用于接受客户端的连接,但是不做任何处理,跟老板一样,不做事
      EventLoopGroup bossGroup = new NioEventLoopGroup();
      // 从线程组, 老板线程组会把任务丢给他,让手下线程组去做任务
      EventLoopGroup workerGroup = new NioEventLoopGroup();
      
      try {
         // netty服务器的创建, ServerBootstrap 是一个启动类
         ServerBootstrap serverBootstrap = new ServerBootstrap();
         serverBootstrap.group(bossGroup, workerGroup)        // 设置主从线程组
                     .channel(NioServerSocketChannel.class) // 设置nio的双向通道
                     .childHandler(new HelloServerInitializer()); // 子处理器,用于处理workerGroup
         
         // 启动server,并且设置8088为启动的端口号,同时启动方式为同步
         ChannelFuture channelFuture = serverBootstrap.bind(8088).sync();
         
         // 监听关闭的channel,设置位同步方式
         channelFuture.channel().closeFuture().sync();
      } finally {
         bossGroup.shutdownGracefully();
         workerGroup.shutdownGracefully();
      }
   }
}

3、创建处理器

import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.http.HttpServerCodec;
/**
 * @Description: 初始化器,channel注册后,会执行里面的相应的初始化方法
 */
public class HelloServerInitializer extends ChannelInitializer<SocketChannel> {

   @Override
   protected void initChannel(SocketChannel channel) throws Exception {
      // 通过SocketChannel去获得对应的管道
      ChannelPipeline pipeline = channel.pipeline();
      
      // 通过管道,添加handler
      // HttpServerCodec是由netty自己提供的助手类,可以理解为拦截器
      // 当请求到服务端,我们需要做解码,响应到客户端做编码
      pipeline.addLast("HttpServerCodec", new HttpServerCodec());
      
      // 添加自定义的助手类,返回 "hello netty~"
      pipeline.addLast("customHandler", new CustomHandler());
   }
}

4、创建助手类

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpHeaderNames;
import io.netty.handler.codec.http.HttpObject;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.HttpVersion;
import io.netty.util.CharsetUtil;

/**
 * @Description: 创建自定义助手类
 */
// SimpleChannelInboundHandler: 对于请求来讲,其实相当于[入站,入境]
public class CustomHandler extends SimpleChannelInboundHandler<HttpObject> {

   @Override
   protected void channelRead0(ChannelHandlerContext ctx, HttpObject msg) 
         throws Exception {
      // 获取channel
      Channel channel = ctx.channel();
      
      if (msg instanceof HttpRequest) {
         // 显示客户端的远程地址
         System.out.println(channel.remoteAddress());
         
         // 定义发送的数据消息
         ByteBuf content = Unpooled.copiedBuffer("Hello netty~", CharsetUtil.UTF_8);
         
         // 构建一个http response
         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());
         
         // 把响应刷到客户端
         ctx.writeAndFlush(response);
      }
      
   }

   @Override
   public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
      System.out.println("channel。。。注册");
      super.channelRegistered(ctx);
   }

   @Override
   public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
      System.out.println("channel。。。移除");
      super.channelUnregistered(ctx);
   }

   @Override
   public void channelActive(ChannelHandlerContext ctx) throws Exception {
      System.out.println("channel。。。活跃");
      super.channelActive(ctx);
   }

   @Override
   public void channelInactive(ChannelHandlerContext ctx) throws Exception {
      System.out.println("channel。。。不活跃");
      super.channelInactive(ctx);
   }

   @Override
   public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
      System.out.println("channeld读取完毕。。。");
      super.channelReadComplete(ctx);
   }

   @Override
   public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
      System.out.println("用户事件触发。。。");
      super.userEventTriggered(ctx, evt);
   }

   @Override
   public void channelWritabilityChanged(ChannelHandlerContext ctx) throws Exception {
      System.out.println("channel可写更改");
      super.channelWritabilityChanged(ctx);
   }

   @Override
   public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
      System.out.println("补货到异常");
      super.exceptionCaught(ctx, cause);
   }

   @Override
   public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
      System.out.println("助手类添加");
      super.handlerAdded(ctx);
   }

   @Override
   public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
      System.out.println("助手类移除");
      super.handlerRemoved(ctx);
   }
}

5、pom文件

<dependency>
    <groupId>io.netty</groupId>
    <artifactId>netty-all</artifactId>
    <version>4.1.25.Final</version>
</dependency>

6、启动main函数

打开浏览器:localhost:8088,出现下面错误情况,如果用postman工具的话,就会发现不报错,因为浏览器会自动关闭。

解决方案:将super.exceptionCauht(ctx,case);注释掉就好了

@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
    //super.exceptionCaught(ctx, cause);
}

© 著作权归作者所有

木九天

木九天

粉丝 179
博文 224
码字总数 171159
作品 0
海淀
程序员
私信 提问
Netty进阶篇之websocket发送消息(8)

序言:Netty进阶篇之简单版websocket发消息(7) 大概和下面的代码就成相似,只不过上一篇博客更加简单一些。 1、pom文件 <dependency> </dependency> 2、index.html <!DOCTYPE html><html><he......

木九天
07/23
36
0
JMeter测试WebSocket的经验总结

版权声明:本文为博主原创文章,未经博主允许不得转载。欢迎访问我的博客 https://blog.csdn.net/smooth00/article/details/81355110 最近有一个微信聊天系统的项目需要性能测试,既然是测试...

smooth00
2018/08/03
0
0
Kotlin + Netty 在 Android 上实现 Socket 的服务端

一. 背景 最近的一个项目:需要使用 Android App 作为 Socket 的服务端,并且一个端口能够同时监听 TCP/Web Socket 协议。 自然而然,项目决定采用 Netty 框架。Netty 服务端在收到客户端发来...

Tony沈哲
08/11
0
0
八问WebSocket协议:为你快速解答WebSocket热门疑问

本文由“小姐姐养的狗”原创发布于“小姐姐味道”公众号,原题《WebSocket协议 8 问》,收录时有优化和改动。感谢原作者的分享。 一、引言 WebSocket是一种比较新的协议,它是伴随着html5规范...

JackJiang2011
04/25
0
0
WebSocket协议详解与c++&c#实现

摘要: 随着手机游戏、H5游戏以及微信小游戏的普及,越来越多的客户端-服务器端的通讯采用websocket协议。Websocket协议是全双工的、基于数据帧的、建立在tcp之上的长连接协议。Websocket的协...

知然
04/25
0
0

没有更多内容

加载失败,请刷新页面

加载更多

SSH安全加强两步走

从 OpenSSH 6.2 开始已经支持 SSH 多因素认证,本文就来讲讲如何在 OpenSSH 下启用该特性。 OpenSSH 6.2 以后的版本多了一个配置项 AuthenticationMethods。该配置项可以让 OpenSSH 同时指定...

xiangyunyan
31分钟前
4
0
C或C++不是C/C++

http://www.voidcn.com/article/p-mucdruqa-ws.html

shzwork
今天
6
0
OSChina 周六乱弹 —— 如何将梳子卖给和尚

Osc乱弹歌单(2019)请戳(这里) 【今日歌曲】 @for_ :划水五分钟,专注两小时。分享Various Artists的单曲《贝多芬第8号钢琴奏鸣曲悲伤的第三乐章》: 《贝多芬第8号钢琴奏鸣曲悲伤的第三乐...

小小编辑
今天
191
8
ES5

什么是ES5:比普通js运行要求更加严格的模式 为什么:js语言本身有很多广受诟病的缺陷 如何:在当前作用域的顶部添加:"use strict" 要求: 1、禁止给未声明的变量赋值 2、静默失败升级为错误...

wytao1995
今天
7
0
c++ 内联函数调用快的原因

见图片分析

天王盖地虎626
今天
4
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部