Notes On TCP/IPv1 Ch.18

0. 貌似在Linux下的tcpdump的输出和TCP/IPv1中所描述的输出有出入, 但是tcpdump手册上面的说法也和TCP/IPv1的一样.

1. tcpdump的输出中, S, F, P, R分别对应SYN, FIN, PSH, RST是个标志位被打开, "."则表示这四个标志位没有被打开. 这四个标志位在一般情况下同时只有一个会被打开. (Page.230)

2. tcpdump的输出中, 只有在S, F, R被打开or报文中数据部分长度不为0的情况下, 序号才会被输出, 而序号后跟随的括号内的值是这个报文的数据部分的长度. (Page.231)

3. 一个链接建立时选择的ISN(initial sequence number)会随着时间的增长而增长, 使用的是无符号的32位整形, 溢出的时候仍然继续增长. ISN自增的目的是阻止在网络中被延迟的报文被误解释成新连接的报文. (page.232)

4. TCP提供全双工的链接, 每个方向的数据流动是独立的(读写独立), 因此一方在收到FIN后并不意味着一定要关闭自己方向的链接, 可以继续向对方发送自己的数据(需要对方没有完全关闭socket而只是关闭了自己方向数据发送, 即使用shutdown函数而非close), 不过这种做法并不常用. (page.233)

5. tcpdump的输出中, 默认除了在发送SYN时会显示报文的实际序号, 在后续的报文显示中都显示报文的相对序号(即当前报文序号-SYN报文序号), 除非使用-S选项. (Page.234)

6. BSDtcp实现中, 有一个每500ms就触发一次的计时器, tcp建立连接发送SYN的时候, 实际上是根据计时器的触发次数进行重传, 而不是时间. 在第一次重传时需要触发12, 所以第一次重传于首次发送SYN的时间差大概为5.5s6s. tcp建立连接超时时间为75s. (Page.235, 236)

7. MSS选项只出现在SYN标志被打开的报文. (Page.237)

8. MSS的计算方法为MTU-20(IP头部固定长度)-20(TCP头部固定长度). (Page.237)

9. 尽管TCP根据对方发送过来的MSS以及自身的MTU控制自己的报文大小以避免报文在传输过程中被分片, 但是如果报文经过中间某个网络的MTU比之前的MSSMTU都要小, 那么分片就只能靠path MTU检测技术来避免. (Page.236, 237, 238)

10. TCP的半关闭利用shutdown函数来实现, 虽然可以使用"建立两个链接一个读, 一个写, 最后根据需要关闭连接"这种方法代替半关闭, 但是半关闭这种方法更为节省资源. (Page.239, 240)

11. TIME_WAIT状态中使用的MSL(maximum segment lifetime)只是用于TIME_WAIT状态的一个计时标准, 而非一个报文在网络上能够"存活"的实际时间. tcp报文封装在ip数据报里, ip数据报根据TTL字段决定是否应被删除, 所以实际决定tcp报文生存时间的是ipTTL字段. (Page.243)

12. 关于TCPUDPSO_REUSEADDR选项的使用存在着不同平台不同实现细节的问题, 详细请看另外一篇文章.

13. TIME_WAIT的作用有二: 一是为了防止主动关闭端最后发送的ACK丢失(如果ACK丢失, 没有TIME_WAIT的话, 对方重传FIN, 会引发RST; 如果有TIME_WAIT的话, 主动关闭端收到FIN会再次发送ACK, 并重设TIME_WAIT计时器); 二是为了等待那些在网络上被延迟的本次连接的报文(收到这样的报文的话会直接删除), 以免它们影响到下一次连接, 被错误解释为新连接的数据. (Page. 243, 246)

14. 关闭过程中有一方会进出FIN_WAIT_2状态(主动关闭的一方), 以等待对方发送数据以及FIN. 如果对方一直不发送FIN, 那么FIN_WAIT_2这个状态会一直维持, 所以许多实现中, 如果程序对一个socket进行完全关闭(close)而不是半关闭(shutdown+SHUT_WR), 那么如果闲置限制675(10分钟+75), 那么就会把这个链接的状态直接从FIN_WAIT_2直接转换成CLOSED状态. (Page.246)

15. 引发RST报文的3种情况: 向不存在的端口发送SYN报文请求连接(UDP向不存在的端口发送数据报则会触发ICMP port unreachable); 连接的一方想要强制关闭这个连接; 一个报文到达一个不存在的端口(一般出现在报文在网络中被延迟这种情况). (Page.247)

16. 在一个TCP连接中, 一方关闭连接的时候, 如果内核中仍有数据未被程序读取, 那么会引发RST的发送, 由于程序未读取该数据, 而这些数据已经被内核确认(发送ACk), 所以对方会认为程序已经接收这些数据, 而实际上这些数据是被废弃的, 所以发送一个RST告知对方自己放弃这个连接. (Page.247)

17. 主动发送RST的方法可以设置SO_LINGER的时间为0, 然后关闭socket. SO_LINGER设置一个徘徊时间(linger), 一般没有设置这个值时, 关闭一个链接后, 内核会自动把余下未发送的数据发送出去并等待确认; 而如果设置了linger时间, 那么内核会尝试在这个指定的时间内把数据发送完毕并等待确认, 如果超过这个时间, 数据仍未发送完或确认完, 那么就删除自己的数据, 发送一个RST给对方. 如果linger时间设置为0的话, 那么会直接发送RST, 不理会是否有数据. (Page.247)

18. 关于RST的序号: 设置为对方发过来最后一个报文的确认号. (Page.248)

19. 如果连接中的一方挂掉而没有发送任何数据告知(FINRST), 那么如果另一方一直不发送数据, 则永远不会知道对方已经挂掉. 可以通过使用额外的机制提早得知对方的情况(keepalive和心跳包). (Page.247)

20. 同步关闭(simultaneous close)的双方都会进入TIME_WAIT状态. (Page.252)

21. TCP选项的结构和BOOTP厂商定制数据的结构基本一样. 无操作(nop)选项是用以在前面填充选项使得选项刚好长度为4的倍数. (Page.253)

22. TCP面向连接, 通过socket pair确定一个连接, 因此一个端口可以为多个连接服务, 多个socketport可以是一样的; UDP无连接, 一个socket只能绑定在一个port. (Page.255)

23. UDP一般可以限制外来IP:port, TCP虽然文档上说明也允许TCP这么做, 但是一般API不提供这个功能. (Page.256)

25. listen函数的backlog参数与服务器可以处理的连接数无关. (Page.258)

26. 三次握手(connect)成功后, 即使服务器没有accept这个连接(即这个连接仍然放在listen函数的队列里), 客户端已经认为可以想服务器发送数据了, 这些发送的数据会由服务器的kernal放进数据队列里. (Page.258)

27. 只要TCP的监听队列仍然有空间, 那么kernal就会为新来的连接进行三次握手, 等到程序被告知有连接进来(accept返回), 这是三次握手已经完成, 链接已经建立了. 程序无法得知链接从哪里来, 控制是否接受这个请求(TLI可以做到, socket API没有这样都功能). (Page.260)

posted on 2011-06-11 17:40  Qwertycen  阅读(322)  评论(0编辑  收藏  举报

导航