2019独角兽企业重金招聘Python工程师标准>>>

最近刚好看到其他几个项目有socket 编程,然后,想了下,在golang 中还没用过socket tcp 编程,于是看了一些im 的协议解析过程,都不是太满意,不是太通用,刚好看到nsq,发现nsq 这部分真是简单粗暴。还用的是标准库的一些东西,非常通用。

该文章后续仍在不断的更新修改中, 请移步到原文地址http://dmwan.cc

nsq 的协议文档地址:https://nsq.io/clients/tcp_protocol_spec.html。

首先,tcp 编程,最麻烦的地方是处理粘包,这个玩意怎么处理,一般是通过分隔符和两次读处理。httppaser 基本会封装这两种,比如tornado 自己封装的readbytes,readuntil,一个是定长读,一个是读到某个标识符为止,中间会为读写分配个缓冲区。这里道理很好理解,定长读,先读约定的header,比如先读4个字节,得到后面有n个字节后,一直循环向buffer 放,而readuntil 每次read 放到buffer,不断find 分隔符。这里的边界条件,不管是python 还是c 写起来都是比较麻烦的事情。

其实golang 里算是比较简单的,看个例子,下面这个是典型,第一行是command,'\n'分隔符结尾,第二行,因为这个command 有参数,用4个字节约定后面body 长度。

Publish a message to a topic:

PUB <topic_name>\n
[ 4-byte size in bytes ][ N-byte binary data ]<topic_name> - a valid string (optionally having #ephemeral suffix)

我们做的时候,只需要有两个函数,一个能readuntil,一个能readbytes就ok,golang 有没?其实golang标准库是有的,分别是bufio.ReadSlice ,对应readuntil, 一个是io.ReadFull, 对应readbytes。

nsq tcp server  流程算是比较清晰的。

1,tcp accept 后,由一个 handle 处理,每个conn 一个IOLoop, 这个IOLoop 会维持这个链接,进行读写。

2, IoLoop 为每个conn 新建一个client 对象,这个对象的Reader 实例化的时候用的是*bufio.Reader,而bufio 封装了一系列的io 方法,这里比较核心的是ReadSlice ,能读到后缀为止。读到的line 按空格解析成command 和 参数 , 由后面反射成不同命令,由Exec 执行。

3, p.Exec 会根据不同的命令,执行不同方法。

4,有的命令会附带body ,这里body 按照协议,是由4 byte 的size 加具体body 构成。这里解析,分两次读取。以pub 为例:

readlen 其实就是ReadFull,client.lenSlice 就是一个[4]byte 的字节数组,所以,其实很明显,两次读取,一个读长度,按长度分配buffer,二次读取body。

func readLen(r io.Reader, tmp []byte) (int32, error) {_, err := io.ReadFull(r, tmp)if err != nil {return 0, err}return int32(binary.BigEndian.Uint32(tmp)), nil
}

上面过程基本就可以 理解整个nsq tcp server 的数据流向了,这里的标准库函数可以很快移植到其他的tcp server 项目中去,只需要构建好自己的protocol,自己的命令反射就ok。

下面分析下 ReadFull 的源码,相比其他语言,按定长读取,放到buffer,这里还是比较有意思的。这样,读到指定长度err 为nil,读不到,数据为bad data。同理,readslice 方式类似。

// ReadAtLeast reads from r into buf until it has read at least min bytes.
// It returns the number of bytes copied and an error if fewer bytes were read.
// The error is EOF only if no bytes were read.
// If an EOF happens after reading fewer than min bytes,
// ReadAtLeast returns ErrUnexpectedEOF.
// If min is greater than the length of buf, ReadAtLeast returns ErrShortBuffer.
// On return, n >= min if and only if err == nil.
func ReadAtLeast(r Reader, buf []byte, min int) (n int, err error) {if len(buf) < min {return 0, ErrShortBuffer}for n < min && err == nil {var nn intnn, err = r.Read(buf[n:])// 这里不会按定长读取1024,而是按照传参,变长读,循环放倒buf,不会出现读多的问题 n += nn}if n >= min {err = nil} else if n > 0 && err == EOF {err = ErrUnexpectedEOF}return
}// ReadFull reads exactly len(buf) bytes from r into buf.
// It returns the number of bytes copied and an error if fewer bytes were read.
// The error is EOF only if no bytes were read.
// If an EOF happens after reading some but not all the bytes,
// ReadFull returns ErrUnexpectedEOF.
// On return, n == len(buf) if and only if err == nil.
func ReadFull(r Reader, buf []byte) (n int, err error) {return ReadAtLeast(r, buf, len(buf))
}

如何防止client 端恶意不传完整参数?设置超时属性就ok。以上。

转载于:https://my.oschina.net/u/2950272/blog/1816971

nsq 源码分析之tcp协议部分相关推荐

  1. activeMQ的源码分析 -TCP通讯机制

    2019独角兽企业重金招聘Python工程师标准>>> activeMQ的源码分析 -TCP通讯机制 博客分类: MQ <IGNORE_JS_OP style="WO ...

  2. NEO从源码分析看共识协议

    2019独角兽企业重金招聘Python工程师标准>>> 0x00 概论 不同于比特币使用的工作量证明(PoW)来实现共识,NEO提出了DBFT共识算法.DBFT改良自股权证明算法(P ...

  3. NSQ源码分析之Topic

    什么是Topic Topic作为nsqd的重要组成部分,里面存在一些有趣的设计,单独开一篇文章进行学习. 每个nsqd实例旨在一次处理多个数据流.这些数据流称为"topics",一 ...

  4. NSQ源码分析之channel

    阅读本文之前,推荐先阅读上一篇对topic的分析. 什么是channel 结合上一篇对topic分析,channel的作用就是将topic的数据进行分流,topic会将发布的消息分配给所有连接的cha ...

  5. Lpms-B2 IMU数据采源码分析 及 TCP/IP握手简单分析

    数据采集代码 源码的数据采集程序,可见第38行其中使用了pollData和update进行数据采集. void LpmsSensorManager::run(void) {MicroMeasure m ...

  6. lwip源码分析 之 DHCP协议实现(一)

    文章目录 一,dhcp协议简介 二,源码解析 2.1 dhcp结构体 2.2 开始广播 2.3 回调接口 a,发送请求 b,等待ack 2.4 其他情况 一,dhcp协议简介 dhcp协议是动态主机配 ...

  7. java socket5源码_Java利用TCP协议实现客户端与服务器通信【附通信源码】

    进行TCP协议网络程序的编写,关键在于ServerSocket套接字的熟练使用,TCP通信中所有的信息传输都是依托ServerSocket类的输入输出流进行的. TCP协议概念 先来了解一下TCP协议 ...

  8. lwip源码解析之 TCP协议 定时器 tcp_slowtmr();和tcp_fasttmr();

    文章目录 一,定时器时钟 二,快速定时任务 三,低速定时任务 1,超时重传 2,保活keepalive 3,删除超时PCB 四,小结 TCP协议中许多地方是需要使用到定时功能的,如定时重传功能,保活k ...

  9. Tor源码分析七 -- 握手协议

    本节主要讲述Tor系统中所用到的握手协议.握手协议分三层:TCP握手:TLS握手:Tor握手.其中Tor握手又分为三个层次:OR握手:链路建立:流建立. TCP的三次握手我想应该学计算机方向的朋友无人 ...

最新文章

  1. 谷歌2020博士生奖研金名单出炉,大陆高校无一人入选
  2. 英特尔九州云99Cloud OpenStack行业应用研讨会
  3. gram矩阵的性质_线性代数(十五)标准正交基(Orthonormal Bases)和Gram-Schmidt正交化...
  4. 《Linux调优工具oprofile的演示分析》
  5. Dockerfile项目环境介绍
  6. 1.20 main()方法
  7. exit()与_exit()的区别
  8. xss_url通关_1-10
  9. 关于 Repeater 控件嵌套的使用。在嵌套中添加 其它控件(如:按钮),并影响其它控件的方法,很重要哦,测试通过。...
  10. Java中判断字符串是否为数字的五种方法
  11. H.264官方软件JM源代码简单分析-解码器ldecod
  12. idea怎么给方法快速添加注释_生完孩子胸部下垂怎么办?来看快速矫正的方法
  13. Android怎样实现毛玻璃效果之Android高级模糊技术
  14. PHP get_class_methods函数用法
  15. 解决ubuntu 用anaconda 安装R 语言后,无法安装R语言package的问题
  16. 学校计算机机房维护年度总结,学校计算机机房的管理和维护建议原稿(全文完整版)...
  17. “新产业50人论坛”之清华龙桂鲁教授:量子信息与创新发展
  18. 计算机系统的优点和缺点,关于ghost系统的解释以及优缺点分析
  19. 工业应用中基于三维模型的6D目标检测综述
  20. 爱你用java代码_[java]__如何用你的编程语言表达至尊宝爱你一万年的浪漫情怀....

热门文章

  1. UIButton设置图片 在导航条上的 不显示
  2. Android呼叫开发系列WebService
  3. zw版【转发·台湾nvp系列Delphi例程】HALCON SmoothImage
  4. Django Web开发学习笔记(4)
  5. Apache Solr schema.xml及solrconfig.xml文件中文注解
  6. Cisco路由器故障诊断技术
  7. 脱机多维数据集CUB文件的生成
  8. Java架构-薪水增长多少,新机会才值得考虑?
  9. 《Linux嵌入式实时应用开发实战(原书第3版)》——3.5 Linux文件系统
  10. 让WPF和SL控件同时支持绑定和赋值