TCP协议入门

作者: MountainKing | 来源:发表于2016-03-09 20:42 被阅读1029次

    Java程序员进阶三条必经之路:数据库、虚拟机、异步通信。

    前言

    想玩转异步通信,不懂TCP协议怎么行?tcpdump目前是最好的命令行抓包工具,所以我选择用它来学习TCP协议。

    使用方法

    tcpdump -i any -X -nn -s0 -S port <port>
    

    tcpdump的参数巨多无比,我只介绍我所掌握的。

    1. -i any,网络接口,any表示任何接口,也可以监听具体的接口,比如-i eth0。
    2. -X,列出十六进制 (hex) 以及 ASCII 的数据包內容。
    3. -nn,不解析域名或端口。比如21端口是FTP端口,我们希望显示21,而非tcpdump自作聪明的将它显示成FTP。
    4. -s0,不限制捕获的内容大小。
    5. -S,打印绝对序列号,这个参数极其重要,稍后介绍。

    三次握手和四次握手

    Paste_Image.png

    开启本地服务监听1234端口,调用tcpdump命令,最后启动客户端:

    telnet localhost 1234
    

    再退出客户端,
    日志输出:

    16:17:43.121895 IP 127.0.0.1.54024 > 127.0.0.1.1234: Flags [S], seq 947792371, win 43690, options [mss 65495,sackOK,TS val 5673569 ecr 0,nop,wscale 7], length 0
        0x0000:  4510 003c bb92 4000 4006 8117 7f00 0001  E..<..@.@.......
        0x0010:  7f00 0001 d308 04d2 387e 29f3 0000 0000  ........8~).....
        0x0020:  a002 aaaa fe30 0000 0204 ffd7 0402 080a  .....0..........
        0x0030:  0056 9261 0000 0000 0103 0307            .V.a........
    16:17:43.121910 IP 127.0.0.1.1234 > 127.0.0.1.54024: Flags [S.], seq 4032343998, ack 947792372, win 43690, options [mss 65495,sackOK,TS val 5673569 ecr 5673569,nop,wscale 7], length 0
        0x0000:  4500 003c 0000 4000 4006 3cba 7f00 0001  E..<..@.@.<.....
        0x0010:  7f00 0001 04d2 d308 f058 afbe 387e 29f4  .........X..8~).
        0x0020:  a012 aaaa fe30 0000 0204 ffd7 0402 080a  .....0..........
        0x0030:  0056 9261 0056 9261 0103 0307            .V.a.V.a....
    16:17:43.121920 IP 127.0.0.1.54024 > 127.0.0.1.1234: Flags [.], ack 4032343999, win 342, options [nop,nop,TS val 5673569 ecr 5673569], length 0
        0x0000:  4510 0034 bb93 4000 4006 811e 7f00 0001  E..4..@.@.......
        0x0010:  7f00 0001 d308 04d2 387e 29f4 f058 afbf  ........8~)..X..
        0x0020:  8010 0156 fe28 0000 0101 080a 0056 9261  ...V.(.......V.a
        0x0030:  0056 9261                                .V.a
    16:17:47.187398 IP 127.0.0.1.54024 > 127.0.0.1.1234: Flags [F.], seq 947792372, ack 4032343999, win 342, options [nop,nop,TS val 5674585 ecr 5673569], length 0
        0x0000:  4510 0034 bb94 4000 4006 811d 7f00 0001  E..4..@.@.......
        0x0010:  7f00 0001 d308 04d2 387e 29f4 f058 afbf  ........8~)..X..
        0x0020:  8011 0156 fe28 0000 0101 080a 0056 9659  ...V.(.......V.Y
        0x0030:  0056 9261                                .V.a
    16:17:47.187736 IP 127.0.0.1.1234 > 127.0.0.1.54024: Flags [F.], seq 4032343999, ack 947792373, win 342, options [nop,nop,TS val 5674585 ecr 5674585], length 0
        0x0000:  4500 0034 3dde 4000 4006 fee3 7f00 0001  E..4=.@.@.......
        0x0010:  7f00 0001 04d2 d308 f058 afbf 387e 29f5  .........X..8~).
        0x0020:  8011 0156 fe28 0000 0101 080a 0056 9659  ...V.(.......V.Y
        0x0030:  0056 9659                                .V.Y
    16:17:47.187742 IP 127.0.0.1.54024 > 127.0.0.1.1234: Flags [.], ack 4032344000, win 342, options [nop,nop,TS val 5674585 ecr 5674585], length 0
        0x0000:  4510 0034 bb95 4000 4006 811c 7f00 0001  E..4..@.@.......
        0x0010:  7f00 0001 d308 04d2 387e 29f5 f058 afc0  ........8~)..X..
        0x0020:  8010 0156 fe28 0000 0101 080a 0056 9659  ...V.(.......V.Y
        0x0030:  0056 9659                                .V.Y
    

    对比日志和图片,基本上可以轻松理解三次握手和四次握手的机制,简单补充一些知识。

    1. 四次握手中的第二次和第三次可以合并成一次。
    2. 如果tcpdump命令没有-S选项的话,三次握手中的第三次就会变成ack 0。原因是:tcp在收到第一条数据包之后,后续的数据包,是使用之前数据包的偏移来显示的。
    3. seq是包的序号,用来解决网络包乱序问题。
    4. ack表示确认收到,用来解决不丢包的问题。
    5. flags是包的类型,主要是用于操控TCP的状态机的,有如下几种状态:
    6. S:SYN(同步),开始会话请求。
    7. A:ACK,应答。
    8. F:FIN,结束会话。
    9. R:RST(复位),中断一个连接。
    10. P:PUSH(推送),数据包立即发送。
    11. U:URG,紧急。
    12. E:ECE,显式拥塞提醒回应。
    13. W:CWR,拥塞窗口减少。
    14. .:没有状态。

    常见瓶颈

    TCP网络应用出问题,十有八九是以下两种情况:

    1. 主动关闭连接方出现大量TIME_WAIT状态。
    2. 被动关闭连接方出现大量CLOSE_WAIT状态

    linux分配给一个用户的文件句柄是有限的,而TIME_WAIT和CLOSE_WAIT两种状态如果一直被保持,那么意味着对应数目的通道就一直被占着,一旦达到句柄数上限,新的请求就无法被处理了,接着应用程序可能返回大量Too Many Open Files异常。
    下图告诉你这两种状态是如何产生的:

    Paste_Image.png
    1. 主动关闭方在关闭连接后,需要发送ACK,假设ACK丢失了,被动关闭一方会重发它的FIN。主动关闭方必须维持一个有效状态信息(TIMEWAIT状态下维持),以便能够重发ACK。如果主动关闭的socket不维持这种状态而进入CLOSED状态,那么主动关闭的socket在处于CLOSED状态时,接收到FIN后将会响应一个RST。被动关闭一方接收到RST后会认为出错了。这就是为什么socket在关闭后,仍然处于TIME_WAIT状态的第一个原因,因为它要等待以便重发ACK。第二个原因是确保连接复用时没有残存的数据。TCP不允许新连接复用TIME_WAIT状态下的socket。处于TIME_WAIT状态的socket在等待两倍的MSL时间以后,将会转变为CLOSED状态,此时通道内不会存在残存数据。
      应用程序无法解决TIME_WAIT问题,我想了一个甩锅的办法是让客户端断开连接,因为谁主动断开谁面临TIMEWAIT。
    2. CLOSE_WAIT需要重点关注。被动关闭方在发送ACK以后会处于CLOSE_WAIT状态,此时只要调用close方法就会发送FIN包,脱离CLOSE_WAIT状态。

    总结

    TCP协议过于复杂,属于很重要但是投入产出比并不高的技术领域,netty提供了非常强大、全面的功能以屏蔽协议细节,所以我不打算在协议上耗太多时间。

    相关文章

      网友评论

        本文标题:TCP协议入门

        本文链接:https://www.haomeiwen.com/subject/roezkttx.html