2015-07-16

经典的 TCP socket 读取报文错误

Views: 32459 | 6 Comments

面试了很多做了多年网络编程的人, 从TCP socket中读取报文这项基本技能, 许多人都做不对. 经典的错误用法是:

char buf[1024]; // 1024或者更大
read(sock, buf, sizeof(buf));
if(parse(buf) == 1){
    // 报文解析完毕
}else{
    // 不是一个完整的报文, 丢弃
}

这是非常经典的错误! 没有任何文档或者手册表明, read()会读到*完整*的报文, 对于read()函数来说, 它只知道字节流, 不知"报文"为何物. read()可能只读到了1个字节的数据就返回... 而且, read()返回的数据的长度, 和对方write()不是一一对应的. 对方调用1次write(), 可能本方要调用1次或者2次或者更多次read().

这个错误之所以经典, 是因为在局域网条件下, 且报文非常小的情况下, 一般(仅仅是一般, 不是100%)write()和read()是一一对应的, 所以, 有些人即使是在BAT公司写了10年网络编程, 也发现不了这个错误. 这个错误就是所谓的"TCP粘包/断包".

看看这个PDF: 高性能并发网络服务器设计与实现.pdf, 看看如何正确地从TCP socket中读取报文. 或者看看 Sim C++ 框架的源码, 了解下 Sim 是如何从 TCP socket 中读取一个报文: https://github.com/ideawu/sim/blob/master/src/server.cpp#L143

Related posts:

  1. 在Linux进行IO的正确姿势
  2. 软件体系结构模式-层
  3. 高性能并发网络服务器设计与实现
  4. Linux 核心编程 – fsync, write
  5. 编写JSP/PHP+MySQL留言本
Posted by ideawu at 2015-07-16 16:41:23

6 Responses to "经典的 TCP socket 读取报文错误"

Leave a Comment