推荐书籍:《TCP/IP详解》
相关读书笔记专栏:《TCP/IP详解》读书笔记
1. TCP vs UDP
TCP 是一种面向连接的、可靠的、字节流服务, UDP 无连接、不可靠的数据报服务。1. 连接方面: TCP 面向连接,交换数据之前必须通过三次握手先建立一个 TCP 连接。在
一个 TCP 中仅有两方彼此通信,多播和广播不能用 TCP。 UDP 是不可靠的传输,传输前不
需要建立链接,可以应用多播和广播实现一对多的通信。
2. 可靠性: TCP 提供端到端的流量控制,对收到的数据进行确认,采用超时重发,对失序
的数据进行重新排序等机制保证数据通信的可靠性。而 UDP 是一种不可靠的服务,接收方
可能不能收到发送方的数据报。
3.TCP 是一种流模式的协议, UDP 是一种数据报模式的协议。进程的每个输出操作都正好
产生一个 UDP 数据报,并组装成一份待发送的 IP 数据报。 TCP 应用程序产生的全体数
据与真正发送的单个 IP 数据报可能没有什么联系。
4. 效率上:一般 TCP 速度慢,传输过程中需要对数据进行确认,超时重发,还要对数据进
行排序。 UDP 没有这些机制所以速度快。数据比例, TCP 头至少 20 个字节, UDP 头 8
个字节,系统组装上 TCP 相对慢。
5. 用途上:用于 TCP 可靠性。而 UDP 速度快,视频,在线游戏多用UDP ,保证实时性。
2. 三次握手
3. 列举你所知道的 tcp 选项,并说明其作用。
1.窗口扩大因子(WSopt):用来增加 TCP 接收窗口的大小。
2.SACK 选择确认选项:使 TCP 只重新发送丢失的包,不用发送后续所有的包,而且提供相
应机制使接收方能告诉发送方哪些数据丢失,哪些数据重发了,哪些数据已经提前收到等。
3.MSS:最大分段大小
4. connect 会阻塞,怎么解决 ?
最有效的是加定时器;也可以采用非阻塞模式( select 检查状态, -1 且 EINPROGRESS 正在
连接,否则错误)。
5. select, epoll
select 的调用过程如下所示:
1. 从用户空间拷贝 fd_set 到内核空间;
2. 注册回调函数__pollwait;
3. 遍历所有 fd,对全部指定设备做一次 poll( poll 是一个文件操作, 有两个参数,一个是
文件 fd 本身,一个是当设备尚未就绪时调用的回调函数__pollwait,这个函数把设备自己特
有的等待队列传给内核, 让内核把当前的进程挂载到其中);
4. 当设备就绪时,设备就会唤醒在自己特有等待队列中的【所有】节点,于是当前进程就
获取到了完成的信号。 poll 文件操作返回的是一组标准的掩码,其中的各个位指示当前的不
同的就绪状态(全 0 为没有任何事件触发),根据 mask 可对 fd_set 赋值;
5. 如果所有设备返回的掩码都没有显示任何的事件触发,就去掉回调函数的函数指针,进
入有限时的睡眠状态,再恢复和不断做 poll,再作有限时的睡眠,直到其中一个设备有事件
触发为止。
6. 只要有事件触发,系统调用返回,将 fd_set 从内核空间拷贝到用户空间,回到用户态,
用户就可以对相关的 fd 作进一步的读或者写操作了。
缺点:
1. 最大并发数限制:使用 32 个整数的 32 位,即 32*32=1024 来标识 fd,虽然可修
改,但是有以下第二点的瓶颈;
2. 效率低:每次都会线性扫描整个 fd_set,集合越大速度越慢;
3.内核/用户空间内存拷贝问题。
poll 的实现和 select 非常相似,只是描述 fd 集合的方式不同, poll 使用 pollfd 结构而不是
select 的 fd_set 结构,其他的都差不多。
poll 传递的是数组头指针和该数组的长度,只要数组的长度不是很长,性能还是很不错的,
因为 poll 一次在内核中申请 4K(一个页的大小来存放 fd),尽量控制在 4K 以内。
epoll 的提升
调用 epoll_create 时,做了以下事情:
内核帮我们在 epoll 文件系统里建了个 file 结点;
在内核 cache 里建了个红黑树用于存储以后 epoll_ctl 传来的 socket;
建立一个 list 链表,用于存储准备就绪的事件。
调用 epoll_ctl 时,做了以下事情:
把 socket 放到 epoll 文件系统里 file 对象对应的红黑树上(已存在立即返回);
给内核中断处理程序注册一个回调函数,告诉内核,如果这个句柄的中断到了,就把它放到
准备就绪 list 链表里。
调用 epoll_wait 时,做了以下事情:
观察 list 链表里有没有数据。有数据就返回,没有数据就 sleep,等到 timeout 时间到后即
使链表没数据也返回。
两种模式的区别:
LT 模式下,只要一个句柄上的事件一次没有处理完,会在以后调用 epoll_wait 时重复返回这
个句柄,而 ET 模式仅在第一次返回。
两种模式的实现:
调用 epoll_wait 会把准备就绪的 socket 拷贝到用户态内存,然后清空准备就绪 list 链表,最
后, epoll_wait 检查这些 socket,如果是 LT 模式,并且这些 socket 上确实有未处理的事件
时,又把该句柄放回到刚刚清空的准备就绪链表。所以, LT 模式的句柄,只要它上面还有事
件, epoll_wait 每次都会返回。
6. 如果 select 返回可读,结果只读到 0 字节,什么情况?
对端已关闭,我们只需要关闭连接
7. socket 什么情况下可读?
1.缓冲区数据量大于最低水位; 2.收到一个 FIN; 3.listen fd 有连接; 4.发送错误
8. 拥塞控制(包括快速重传和快速恢复)
9. 流量控制( 滑动窗口)
拥塞窗口:发送方的,整体的; 通告窗口:接收方的,个体的。
10. 4 个定时器
1.重传定时器适用于当希望收到另一端的确认。
2.坚持( persist)定时器使窗口大小信息保持不断流动,即使另一端关闭了其接收窗口。
3.保活( keepalive)定时器可检测到一个空闲连接的另一端何时崩溃或重启。
4.2MSL 定时器测量一个连接处于 TIME_WAIT 状态的时间。
11. Udp 调用 connect
让内核记下 ip:port(可多次调用,断开旧的,指定新的)
1.安全:只从指定对端收消息; 2.会返回异步错误
12. Epoll 水平触发不断调用 write:使用边沿触发,并在应用层标记。
13. Client 断电:服务器可 定时 or keep-alive
14. 套接字选项:
SO_KEEPALIVE , SO_LINGER , SO_REUSEADDR(使用 IP 别名技术托管多个 HTTP 服务器网点、
众所周知的服务快速重启)
15. TIME_WAIT:保险状态, 1.可靠实现连接的终止;2.允许老的重复分组在网络中消逝。
16. 链路层:对应 OSI 的物理层和数据链路层, 完成数据帧的实际发送和接收。
网络层:处理分组在网络中的活动,例如路由选择和转发等,这一层主要包括 IP 协议、
ARP、 ICMP 协议等。
传输层:主要功能是提供应用程序之间的通信,这一层主要是 TCP/UDP 协议。
应用层:用来处理特定的应用,针对不同的应用提供了不同的协议,例如进行文件传输
时用到的 FTP 协议,发送 email 用到的 SMTP 等。