在《》一节中讲到,可以运用 write()/send() 函数发送数据,运用 read()/recv() 函数接纳数据,本节就来看看数据是若何传递的。

socket缓冲区

每一个 socket 被创立后,都邑分派两个缓冲区,输出缓冲区和输入缓冲区。
write()/send() 并不立刻向收集中传输数据,而是先将数据写入缓冲区中,再由TCP协定将数据从缓冲区发送到目的机械。一旦将数据写入到缓冲区,函数就可以胜利前往,不论它们有没有抵达目的机械,也不论它们何时被发送到收集,这些多是TCP协定担任的工作。
TCP协定自力于 write()/send() 函数,数据有能够刚被写入缓冲区就发送到收集,也能够在缓冲区中不时积存,屡次写入的数据被一次性发送到收集,这取决于事先的收集状况、以后线程能否闲暇等诸多要素,不由程序员掌握。
read()/recv() 函数也是如斯,也从输出缓冲区中读取数据,而不是直接从收集中读取。

图:TCP套接字的I/O缓冲区表示图


这些I/O缓冲区特征可整顿如下:

  • I/O缓冲区在每一个TCP套接字中独自存在;

  • I/O缓冲区在创立套接字时主动生成;

  • 即便封闭套接字也会持续传送输入缓冲区中遗留的数据;

  • 封闭套接字将丧失输出缓冲区中的数据。


输出输入缓冲区的默许巨细普通多是 8K,可以经过 getsockopt() 函数获取:

unsigned optVal; int optLen = sizeof(int); getsockopt(servSock, SOL_SOCKET, SO_SNDBUF, (char*)&optVal, &optLen); printf("Buffer length: %d\n", optVal);

运转后果:
Buffer length: 8192

这里仅给出示例,前面会具体解说。

壅塞形式

关于TCP套接字(默许状况下),当运用 write()/send() 发送数据时:
1) 起首会反省缓冲区,假如缓冲区的可用空间长度小于要发送的数据,那么 write()/send() 会被壅塞(暂停履行),直到缓冲区中的数据被发送到目的机械,腾出足够的空间,才叫醒 write()/send() 函数持续写入数据。
2) 假如TCP协定正在向收集发送数据,那么输入缓冲区会被锁定,不许可写入,write()/send() 也会被壅塞,直到数据发送终了缓冲区解锁,write()/send() 才会被叫醒。
3) 假如要写入的数据大于缓冲区的最大长度,那么将分批写入。
4) 直到一切数据被写入缓冲区 write()/send() 才干前往。
当运用 read()/recv() 读取数据时:
1) 起首会反省缓冲区,假如缓冲区中无数据,那么就读取,不然函数会被壅塞,直到收集上无数据到来。
2) 假如要读取的数据长度小于缓冲区中的数据长度,那么就不克不及一次性将缓冲区中的一切数据读出,残剩数据将不时积存,直到有 read()/recv() 函数再次读取。
3) 直到读取到数据后 read()/recv() 函数才会前往,不然就不断被壅塞。
这就是TCP套接字的壅塞形式。所谓壅塞,就是上一步举措没有完成,下一步举措将暂停,直到上一步举措完成后才干持续,以坚持同步性。

TCP套接字默许状况下是壅塞形式,也是最常用的。当然你也可以更改为非壅塞形式,后续我们会解说。