在《主程的晋升攻略(3):IP、DNS和CDN》中,一次网络请求经过DNS解析知道了目的IP,如今就要发出网络包,这里我们说一说TCP的相关话题。

TCP是一种流式协议

讲网络编程的教科书一般都会对TCP的可靠传输,api使用方法做具体说明,但对于TCP是一种流式协议解说的不多,但这背后隐藏着非常重要的一个知识点。先做个名词定义方便交流,这里的“消息”是指应用层的一个完整的协议包。



流式协议的特点是什么?就像流水连续不断那样,消息之间没有边界。比如send了3条消息。各自是100字节、50字节、80字节。recv时可能收到的是230字节,就是说一次recv收到了3条消息,须要应用逻辑自己对recv到的数据进行分析,得出完整的消息。

能一次recv到多个消息,也可能一次recv到一个半消息或半个消息,都是有可能的,这就是流式协议的特点。有的文章讲的粘包也是这个概念。

消息分包

既然TCP是一种流式协议,须要应用层自己来分析出完整的消息。那有哪些方式来确定一个完整消息呢?这个就是应用层通讯协议设计的工作了。



先看看最常见的HTTP协议是怎样来分包的。

HTTP协议是一种文本协议(非二进制协议)。用\r\n\r\n来切割消息头和消息体,HTTP请求的消息头中有Content-Length来告知消息体有多大,假设没有该字段就表示无消息体,GET请求大多是这样。HTTP响应的消息头中,或者有Content-Length,或者有Transfer-Encoding: chunked告知以chunk模式分析消息体。

HTTP请求





HTTP响应1:Conetent-Length









HTTP响应2:Transfer-Encoding

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvVGhpbmtyeQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="">





HTTP用\r\n\r\n来切割消息头和消息体,这样的用特定字符/字符串来切割或分包的方式。还有不少协议用到。比如FTP/SMTP/POP3都是用\n来作为一个命令结束的标志。这样的消息分包的方式,须要应用层去扫描已recv到的数据,性能上还不够高效,代码不严谨的还easy被攻击。在须要自己定义协议的项目中。不少选择用二进制协议,解析高效,安全性更好些。

最简单的二进制协议分包方式是消息的头4个字节表示消息的总长度。这样的方式还须要对最大消息长度做个限制。比如64K或1024K大小,避免超大数据包对接收方缓冲区的破坏。更进一步的。能够增加简单校验方法。

比如消息头1个字节固定式0x2,消息的最后1个字节固定式0x3。消息总长度放在第2~5字节。这样收到完整消息后。假设头尾不是0x2和0x3,就直接异常处理。

协议设计

消息分包是协议设计的一个工作,协议设计的话题还不少,这里以HTTP协议为例。简要的说说里面设计的点。自己设计的协议也能够对比着有选择的使用,原理是共通的。



由消息头+消息体组成:空行切割HTTP head和body,HTTP头的每一行以\r\n结尾,空行就是\r\n\r\n

消息分包:如上所述。HTTP用Content-Length和Transfer-Encodeing来分包

消息压缩:请求中有Accept-Encoding字段。响应中用Content-Encoding字段表明压缩方式,一般採用gzip压缩

消息加密:https  (SSL: Secure Socket Layer)

消息ID:URL就是消息ID

响应的状态码:第一个数字定义了响应的类别。

    1xx:指示信息--表示请求已接收,继续处理

    2xx:成功--表示请求已被成功接收、理解、接受

    3xx:重定向--要完毕请求必须进行更进一步的操作

    4xx:client错误--请求有语法错误或请求无法实现

    5xx:server端错误--server未能实现合法的请求

协议版本号号: HTTP/1.1中的1.1就是HTTP 1.1版本号

长连接:请求中Connection: keep-alive表示希望server保持连接,降低TCP连接的开销

字符集: Content-Type字段表明了字符集。比如: Content-Type: text/html; charset=gb2312

字符转义:URL中的參数须要做URL转义处理,比如http://xx.com/do?

name=t%2F%3F%23%3Daa表示name为t/?

#=aa

在我们自己设计协议时,能够有选择的使用。假设消息比較大,能够採用支持压缩;假设要兼容多个版本号的协议,那版本号号不可缺少。假设採用二进制协议。字符集和字符穿衣的用处不大。

-------- 切割线 ---------

主程的晋升攻略(1):重要的引言

主程的晋升攻略(2):技术篇概要

主程的晋升攻略(3):IP、DNS和CDN

主程的晋升攻略(5):HTTP协议和二进制协议的对照

主程的晋升攻略(6):CGI和FastCGI





推荐wecode程序猿云笔记──为程序猿而生的开源、简洁高效的云笔记软件,使用有道云做云端存储。

★ 【语法高亮】眼下支持 C/C++、C#、Pascal、Java、VB.Net、XML、HTML、Python、SQL等多种方。

★ 【云端存储】除了本地笔记本外,还添加了云存储功能。眼下使用有道云笔记做为云存储。

★ 【文档加密】提供了文档加密功能,确保敏感文档的安全性。

★ 【多个本地笔记本】支持多个本地笔记本,你可以新建本地笔记本、打开、压缩和备份本地笔记本。

★ 【文章附件】可以为每一个文章加入多个附件,并可以在暂时文件夹中打开附件、导出附件。有道云的附件也存储在云端。

主程的晋升攻略(4):TCP、消息分包和协议设计的更多相关文章

  1. 主程的晋升攻略(3):IP、DNS和CDN

    有段时间我面试程序猿时,喜欢问这个问题:局域网IP有哪些IP段?由这个问题再追问NAT(网络地址转换). 为什么不是每一个设备一个公网IP? 先说个关于QQ的小故事,最早开发QQ时.小马哥他们也没想到 ...

  2. TCP、消息分包和协议设计

    TCP是一种流式协议 TCP是一种面向连接的.可靠的.基于字节流的传输层通信协议. 流式协议的特点是什么?就像流水连续不断那样,消息之间没有边界.例如send了3条消息(这里的“消息”是指应用层的一个 ...

  3. [国嵌攻略][091][TCP网络程序设计]

    server.c #include <sys/socket.h> #include <netinet/in.h> #include <strings.h> #inc ...

  4. BOOST 线程完全攻略 - 扩展 - 线程消息通讯

      // controlled_module_ex.hpp : controlled_module类的扩展 // 增强线程之间消息通讯 // 增加线程安全启动和安全关闭功能 // 增加定时器功能 #p ...

  5. [国嵌攻略][156][I2C自编设备驱动设计]

    AT24C08的驱动在Linux内核中已经提供,在/drivers/misc/eeprom/at24.c文件中.在对应的probe函数中有一个创建/sys/.../eeprom文件的函数,应用程序通过 ...

  6. 令牌Token和会话Session原理与攻略

    本篇文章将从无到完整的登录框架或API详细讲述登录令牌原理.攻略等安全点. 有些协议或框架也喜欢把令牌叫票据(Ticket),不论是APP还是Web浏览器,很多框架或协议都用到了本文所说的这套类似的认 ...

  7. c++小学期大作业攻略(二)整体思路+主界面

    写在前面:如果我曾经说过要在第一周之内写完大作业,那……肯定是你听错了.不过如果我在写的时候有攻略看的话应该可以轻松地在4~5天内做完,然后觉得写攻略的人是个小天使吧(疯狂暗示).出于给大家自由发挥的 ...

  8. Windows Socket五种I/O模型——代码全攻略(转)

    Winsock 的I/O操作: 1. 两种I/O模式 阻塞模式:执行I/O操作完成前会一直进行等待,不会将控制权交给程序.套接字 默认为阻塞模式.可以通过多线程技术进行处理. 非阻塞模式:执行I/O操 ...

  9. puppet完全攻略(一)puppet应用原理及安装部署

    puppet完全攻略(一)puppet应用原理及安装部署 2012-06-06 18:27:56 标签:puppet puppet应用原理 原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出 ...

随机推荐

  1. webpack基础知识点

    webpack 是一个现代的 JavaScript 应用程序的模块打包器(module bundler). 入口(Entry) webpack 将创建所有应用程序的依赖关系图表(dependency ...

  2. 【【henuacm2016级暑期训练】动态规划专题 N】Valid Sets

    [链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 给你一棵树. 让你统计其中子树T的数量. 这个子树T要满足最大值和最小值之差小于等于d 树形DP 可以枚举点root为子树的根. 统 ...

  3. Spring中 @Autowired标签与 @Resource标签 的区别(转)

    spring不但支持自己定义的@Autowired注解,还支持由JSR-250规范定义的几个注解,如:@Resource. @PostConstruct及@PreDestroy. 1. @Autowi ...

  4. leetCode(24):Binary Search Tree Iterator

    Implement an iterator over a binary search tree (BST). Your iterator will be initialized with the ro ...

  5. Android native CursorWindow数据保存原理

    我们通过Uri查询数据库所得到的数据集,保存在native层的CursorWindow中.CursorWindow的实质是共享内存的抽象,以实现跨进程数据共享.共享内存所採用的实现方式是文件映射. 在 ...

  6. android init进程分析 init脚本解析和处理

    (懒人近期想起我还有csdn好久没打理了.这个android init躺在我的草稿箱中快5年了.略微改改发出来吧) RC文件格式 rc文件是linux中常见的启动载入阶段运行的文件.rc是run co ...

  7. D3js-绘制地图时出现过小, 设置scale还是无效 的解决方法

    使用d3绘制某个地市的地图时,把scale成非常大但是还是无法达到想要的效果. //---------------------------------------------------------- ...

  8. bzoj2768: [JLOI2010]冠军调查(双倍经验最小割)

    2768: [JLOI2010]冠军调查 题目:传送门 题解: 双倍经验(1934) 代码: #include<cstdio> #include<cstring> #inclu ...

  9. javaScript常用知识点有哪些

    javaScript常用知识点有哪些 一.总结 一句话总结:int = ~~myVar, // to integer | 是二进制或, x|0 永远等于x:^为异或,同0异1,所以 x^0 还是永远等 ...

  10. java布局管理

    FlowLayout :组件在一行中按加入的先后顺序从左至右水平排列,排满后折行,每行中的组件都居中排列.BorderLayout:把容器空间划分为北.南.西.东.中五个区,每加入一个组件都应说明把这 ...