前言

  •   软件通信七层结构(osi模型)中由协议套协议最终组成最高级应用层协议(http等等),下三层结构偏向与数据通信,上三层更偏向于数据处理,中间的传输层则是连接上三层与下三层之间的桥梁,每一层都做不同的工作,上层协议依赖与下层协议。
  •   七层结构的最主要功能就是帮助不同系统的主机在不同的网络中进行数据传输。
  •   数据传输层:tcp、udp协议,tcp协议依赖互联网协议(ip层协议)。
  •   socket在第五层会话层,它并不是一个协议,而是一组接口(api),更是一个规范,为了方便使用底层协议而存在的一种抽象层。
  •   websocket,http 等协议都是应用层协议(更面向于用户),依赖于传输层tcp协议。
  •   websocket 在进行通信时,使用了http进行一次握手,数据传输使用tcp通道传输。
  •   socket更像是一种网络编程的概念,是抽象出来的。

tcpSocket 与 websocket 的区别:

  1.  tcpSocket是tcp的协议传输,直接进行tcp的三次握手:client向server发送请求报文,server回复ack报文并分配资源,client发送报文并分配资源,连接建立。
  2.  websocket是基于tcp的应用层协议,采用一次HTTP握手。其发送的请求报文和socket是有区别的。

本片文章目的:

  使用netty同端口监听tcpsocket和websocket消息传输。

实现思想:

  在netty编程中,对于不同的消息肯定需要不同的编解码来处理,所以我们需要利用netty具有动态增删处理器handle的功能。

  而从上文中我们知道websocket第一次是采用http握手的,因此debug握手请求,知道他的请求头部是GET方式。

  所以我们需要根据这点来判断接收的消息是websocket还是tcpsocket。

 

1.判断handle如下:

/**
* 协议初始化解码器.
*
* 用来判定实际使用什么协议.</b>
*
*/
public class SocketChooseHandle extends ByteToMessageDecoder {
/** 默认暗号长度为23 */
private static final int MAX_LENGTH = 23;
/** WebSocket握手的协议前缀 */
private static final String WEBSOCKET_PREFIX = "GET /"; @Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
String protocol = getBufStart(in);
if (protocol.startsWith(WEBSOCKET_PREFIX)) {
SpringApplicationContextHolder.getSpringBeanForClass(PipelineAdd.class).websocketAdd(ctx); ctx.pipeline().remove(LengthFieldBasedFrameDecoder.class);
ctx.pipeline().remove(LengthFieldPrepender.class);
ctx.pipeline().remove(BytebufToByteHandle.class);
} in.resetReaderIndex();
ctx.pipeline().remove(this.getClass()); } private String getBufStart(ByteBuf in){
int length = in.readableBytes();
if (length > MAX_LENGTH) {
length = MAX_LENGTH;
} // 标记读位置
in.markReaderIndex();
byte[] content = new byte[length];
in.readBytes(content);
return new String(content);
}
}

说明:判断是否是GET /协议开始的消息,如果是,则是websocket,那么移除后面的socket编解码器,添加websocket编解码器。然后删除自己(将自身删除后,此连接之后的消息将不再进入这个handle,直接走安排好的对应handle串行处理器。而不是所有连接)。

2.接下来我们将上述handle判断器加入到消息来的编解码器前方。

实现代码如下:

     // 1.socket方式服务
// 设置N秒没有读到数据,则触发一个READER_IDLE事件。
pipeline.addLast(new IdleStateHandler(readerIdleTime,0,0, TimeUnit.SECONDS));
pipeline.addLast("active",new ChannelActiveHandle());
pipeline.addLast("socketChoose",new SocketChooseHandle()); //tcpsocket编码解码handle,如果是websocket链接,会将其删除
pipeline.addLast("lengthEncode",new LengthFieldPrepender(4, false));
pipeline.addLast("lengthDecoder",new LengthFieldBasedFrameDecoder(2000, 0, 4,0, 4));
pipeline.addLast(bytebufToByteHandle); //因为接收类型的泛型不对,所以在websocket握手的时候不会进入该handle
//此handle为最后的socket消息分解,web和tcp通用
pipeline.addLast("byteToBuf",byteToByteBufHandle);
pipeline.addLast("protocolResolve",protocolResolveHandle);

说明:

IdleStateHandler  心跳处理器
active 活跃连接处理器
socketChoose 前文所述的判断消息协议处理器
lengthEncode tcp连接的拆包粘包编码处理器(用来在消息前面附加4个字节的长度信息)
lengthDecoder tcp连接的拆包粘包解码处理器(长度判断)
bytebufToByteHandle  自定义处理器,用来将bytebuf转成我们需要的byte[]。
byteToBuf  自定义处理器,用来将要发出的消息从byte[]装成bytebuf。
protocolResolve 自定义处理器,处理消息,找到路由handle以及处理逻辑

3.websocket需要的编解码器
代码如下
  public  void websocketAdd(ChannelHandlerContext ctx){

        // HttpServerCodec:将请求和应答消息解码为HTTP消息
ctx.pipeline().addBefore("byteToBuf","http-codec",new HttpServerCodec()); // HttpObjectAggregator:将HTTP消息的多个部分合成一条完整的HTTP消息
ctx.pipeline().addBefore("byteToBuf","aggregator",new HttpObjectAggregator(65535)); // ChunkedWriteHandler:向客户端发送HTML5文件
ctx.pipeline().addBefore("byteToBuf","http-chunked",new ChunkedWriteHandler()); ctx.pipeline().addBefore("byteToBuf","WebSocketAggregator",new WebSocketFrameAggregator(65535)); // 在管道中添加我们自己的接收数据实现方法
ctx.pipeline().addBefore("byteToBuf","ws-handShake",wsHandShakeServerHandle); // 后续直接走消息处理
ctx.pipeline().addBefore("byteToBuf","wsPack",wsPacketHandle); // 编码。将通用byteBuf编码成binaryWebSocketFrame.通过前面的编码器
ctx.pipeline().addBefore("byteToBuf","bufToFrame",bytebufToBinaryFrameHandle); }

说明:

wsPacketHandle   自定义处理器,将接收的BinaryWebSocketFrame消息转成byte[]供protocolResolve处理。
bytebufToBinaryFrameHandle  自定义处理器,将需要发送的byte转成BinaryWebSocketFrame供websocket的编码器处理。


详细代码请参考nafos-network: https://gitee.com/huangxinyu/BC-NETTYGO


NAFOS

一个基于netty的轻量级高性能服务端框架。

简介

nafos是一个基于netty的高性能服务器框架,其目的在于易上手,易扩展,让开发人员更致力于业务开发。 在前后端分离的web架构上,或者APP,手游,nafos都是一个很不错的选择。

除此之外,sample中也给出了超简单的扩展方案,使得nafos在分布式扩展上能更胜一筹。

文档

特点

  • 1、简单易用:通过简单的配置文件即可建立完善的启动方案,然后就可以开心的关注业务代码了;
  • 2、串行设计 :单用户的所有请求都是串行进行,完美解决单用户并发问题,减少锁的使用;
  • 3、高性能:网络层采用netty作为中间件,同等配置及优化条件下,相比tomcat性能可提升一倍;
  • 4、易扩展:整合了springBoot,可完美支持spring大家族系列;
  • 5、强兼容: 可单机同时支持HTTP,TCP,websocket等服务,小规模应用下不用多开占用资源;
  • 6、工具类丰富:封装所有开发中常见工具类可直接调用;
  • 7、房间策略:封装常见游戏的房间策略,开房,比赛,聊天可直接调用,无需多写;
  • 8、模块化:多个模块之间相互解耦,喜欢哪个用哪个,不喜欢直接丢弃。
  • 9、脚本支持:内有现成的shell脚本可以直接使用,开关机,数据库备份等;
  • 10、自带分布式限流器,有IP策略和总流量策略等漏桶限流,抵御攻击。
  • 11、丰富教程:除了详细文档外,在sample模块中还有多模块使用案例,开发无忧~

netty同端口监听tcp和websocket协议的更多相关文章

  1. swoole多端口监听

    今天测试swoole写webserver实现多端口监听.记录下爬过的坑:关于tcp协议监听触发不到receive!!!!! 首先上服务端代码 class Http { /** * 服务实例 * @va ...

  2. 获取运行端口监听的用户身份auth-owner

    获取运行端口监听的用户身份auth-owner   Windows系统提供工作在TCP 113端口的授权服务(Authentication Service),用来判断TCP连接的用户.Nmap的aut ...

  3. 利用 netsh 给 mysql 开启多端口监听

    利用 netsh 给 mysql 开启多端口监听 标题党,实际并不是真的多端口监听,只是端口转发而已. 由于某种特殊原因需要 mysql 服务器多个端口监听. mysql 服务器本身是不支持的,但可以 ...

  4. ZooKeeper(二):多个端口监听的建立逻辑解析

    ZooKeeper 作为优秀的分布系统协调组件,值得一探究竟.它的启动类主要为: 1. 单机版的zk 使用 ZooKeeperServerMain 2. 集群版的zk 使用 QuorumPeerMai ...

  5. nodejs 80端口监听失败及NODE_PATH不起作用的问题

    nodejs做web服务器,打开80时报错:Error: listen EACCES 0.0.0.0:80 80端口监听失败,是因为1024以下的端口需要root权限,需要sudo或su之后执行.但这 ...

  6. asp.net core 多端口监听&日志服务

    1 配置多个端口监听 HostingAbstractionsWebHostBuilderExtensions. public static IWebHostBuilder UseUrls(this I ...

  7. 多进程端口监听 How nginx processes a request Server names

    网络编程( 六):端口那些事儿 - 知乎专栏  https://zhuanlan.zhihu.com/p/20365900 不停服务reload.restart 多进程端口监听 我们都有一个计算机网络 ...

  8. TNS-12541: TNS: 无监听程序 TNS-12560: TNS: 协议适配器错误 TNS-00511: 无监听程序

    文章转自:http://www.luocs.com/archives/464.html 此文版权归作者 – yaogang所有,转载请注明yaogang©www.luocs.com. Luocs说:这 ...

  9. ORACLE RAC 下非缺省端口监听配置(listener.ora tnsnames.ora)

    不论是单实例还是RAC,对于非缺省端口下(1521)的监听器,pmon进程不会将service/instance注册到监听器,即不会实现动态注册.与单实例相同,RAC非缺省端口的监听器也是通过设置参数 ...

随机推荐

  1. SQL强化练习(面试与学习必备)

    一.经典选课题A 1.1.请同时使用GUI手动与SQL指令的形式创建数据库.表并添加数据. 题目:设有一数据库,包括四个表:学生表(Student).课程表(Course).成绩表(Score)以及教 ...

  2. java笔记----面试题总结(一)【转】

    1.面向对象的特征有哪些方面? 答:面向对象的特征主要有以下几个方面: - 抽象:抽象是将一类对象的共同特征总结出来构造类的过程,包括数据抽象和行为抽象两方面.抽象只关注对象有哪些属性和行为,并不关注 ...

  3. 用cmd命令行编译JAVA程序时出现“找不到或无法加载主类”

    今天复习Java基础知识时,使用cmd命令窗口进行编译Java文件发现了如下问题: 网上有很多的解决方法,和问题出现的讨论,以下方法是解决我出现这个问题方式. 解决方式: 重点是圈住的部分. 下面是我 ...

  4. c/c++ 字节对齐

    c 字节对齐 概念: 结构体里会包括各种类型的成员,比如int char long等等,它们要占用的空间不同,系统为一个结构体开辟内存空间时,会有2种选择. 第一种:节省空间的方案,以上面的列子来说的 ...

  5. LeetCode算法题-Delete Node in a Linked List(Java实现)

    这是悦乐书的第197次更新,第204篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第60题(顺位题号是235).编写一个函数来删除单链表中的节点(尾部除外),只允许访问该 ...

  6. FCM算法的matlab程序(初步)

    FCM算法的matlab程序 在https://www.cnblogs.com/kailugaji/p/9648430.html文章中已经介绍了FCM算法,现在用matlab程序实现它. 作者:凯鲁嘎 ...

  7. java使用elasticsearch实现集群管理

    本篇博客主要是查看集群中的相关信息,具体请看代码和注释 @Test public void test45() throws UnknownHostException{ //1.指定es集群 clust ...

  8. 如何使用微信web开发者工具调试企业微信

    最近因工作需要围绕着企业微信来进行调试,从而掏出了我的微信web开发者工具,在进行授权的时候微信web开发者工具成功的提示了我:“您未绑定企业微信开发者权限”.那么关键来了,因为我也百度过,发现也有很 ...

  9. 概率期望dp

    对于概率dp,我一直都弄得不是特别明白,虽然以前也有为了考试去突击过,但是终究还是掌握得不是很好,所以决定再去学习一遍,把重要的东西记录下来. 1.hdu4405 Description 在一个 \( ...

  10. 各种缓存(Memcached、Redis、RabbitMQ、SQLlchemy)

    Memcached Memcached 是一个高性能的分布式内存对象缓存系统,用于动态Web应用以减轻数据库负载.它通过在内存中缓存数据和对象来减少读取数据库的次数,从而提高动态.数据库驱动网站的速度 ...