这似乎是一个非常简单的话题, 就跟"是个人就能做网站"一样, 你可能也认为"是个人就能写使用TCP socket的网络程序". 不过, 下面介绍的几个基本的原理的做法, 你可能并没有理解.
TCP是一种流式的协议, 简单的说, TCP不检查数据的语义, 更不会检查数据的边界, 而应用层一般使用的是报文协议, 所以会有所谓的"粘包""拆包"问题. 为此, 产生了一些特定的用法和模式.
任何应用程序, 都必须先进行报文协议设计. 虽然有些人捂上耳朵叫道"我不需要报文协议", 但是, 他还是需要进行报文协议设计. 有几种方式可用来设计报文协议:
1. 明确声明报文数据的长度.
2. 使用分隔符.
3. 发送方发送完数据后关闭连接.
第3种是socket的特定用法.
报文设计方法1: 明确声明报文数据的长度
此种方法一般较为常用, 因为兼容性好性能高. 一会介绍方法2的时候你就知道了. 一般会在数据的最前面用固定的几个字节存储一个二进制整数, 显示后面的数据的长度. 不过, 这是比较接近硬件底层报文协议设计. 应用层一般不这样, 在数据的前端固定几个字节存储ASCII数字, 前端补字符串'0', 或者在数字串后面跟换行符'\n', 这是一种和2的方法的混用.
报文设计方法2: 使用分隔符
前面介绍方法1的时候提过了, 使用分隔符来分隔报文, 然后在一般的语言都有 split() 函数, 用起来简单. 不过, 使用分隔符有一个缺点, 就是要进行数据转义, 避免报文数据中带有分隔符, 那就不好了. 此种方法还有一个缺点, 就是要遍历每一个字节, 查找分隔符, 性能不好. 介绍方法1的时候, 因为我们明确知道是数字串后面跟换行符, 所以不需要转义, 不会有转义性能损失, 同时数字串一般很短, 也可以忽略遍历性能损失.
报文设计方法3: 发送方发送完数据后关闭连接
这是 HTTP 1.0 采用的方式, HTTP 1.0 会在发送完响应后关闭连接(当然, 发送完请求后不能关闭连接, 所以可想而知, HTTP 1.0 必然使用方法1或者方法2, 你可以自己去学习了解). 这种方法不常用, 因为适用场景非常窄, 功能差.
Continue reading »