tcp学习

what is TCP

简介

传输控制协议(英语:Transmission Control Protocol,缩写:TCP)是一种面向连接的、可靠的、基于字节流传输层通信协议,由IETFRFC 793定义。在简化的计算机网络OSI模型中,它完成第四层传输层所指定的功能。用户数据报协议(UDP)是同一层内另一个重要的传输协议。

概念

数据在TCP层称为流(Stream),数据分组称为分段(Segment)。作为比较,数据在IP层称为Datagram,数据分组称为分片(Fragment)。 UDP 中分组称为Message。

**CWR(Congestion Window Reduce):拥塞窗口减少标志被发送主机设置,用来表明它接收到了设置ECE标志的TCP包,发送端通过降低发送窗口的大小来降低发送速率

ECE(ECN Echo):ECN响应标志被用来在TCP3次握手时表明一个TCP端是具备ECN功能的,并且表明接收到的TCP包的IP头部的ECN被设置为11。更多信息请参考RFC793。

URG(Urgent):该标志位置位表示紧急(The urgent pointer) 标志有效。该标志位目前已经很少使用参考后面流量控制和窗口管理部分的介绍。

ACK(Acknowledgment):取值1代表Acknowledgment Number字段有效,这是一个确认的TCP包,取值0则不是确认包。后续文章介绍中当ACK标志位有效的时候我们称呼这个包为ACK包,使用大写的ACK称呼。

PSH(Push):该标志置位时,一般是表示发送端缓存中已经没有待发送的数据,接收端不将该数据进行队列处理,而是尽可能快将数据转由应用处理。在处理 telnet 或 rlogin 等交互模式的连接时,该标志总是置位的。

RST(Reset):用于复位相应的TCP连接。通常在发生异常或者错误的时候会触发复位TCP连接。

SYN(Synchronize):同步序列编号(Synchronize Sequence Numbers)有效。该标志仅在三次握手建立TCP连接时有效。它提示TCP连接的服务端检查序列编号,该序列编号为TCP连接初始端(一般是客户端)的初始序列编号。在这里,可以把TCP序列编号看作是一个范围从0到4,294,967,295的32位计数器。通过TCP连接交换的数据中每一个字节都经过序列编号。在TCP报头中的序列编号栏包括了TCP分段中第一个字节的序列编号。类似的后续文章介绍中当这个SYN标志位有效的时候我们称呼这个包为SYN包。

FIN(Finish):带有该标志置位的数据包用来结束一个TCP会话,但对应端口仍处于开放状态,准备接收后续数据。当FIN标志有效的时候我们称呼这个包为FIN包。

运行

TCP协议的运行可划分为三个阶段:连接创建(connection establishment)、数据传送(data transfer)和连接终止(connection termination)。操作系统将TCP连接抽象为套接字表示的本地端点(local end-point),作为编程接口给程序使用。在TCP连接的生命期内,本地端点要经历一系列的状态改变。

连接创建(3次握手)

第一次握手(client -> server)

IP 127.0.0.1.63515 > 127.0.0.1.8888: Flags [S], seq 332753718, win 65535, options [mss 16344,nop,wscale 6,nop,nop,TS val 1572533652 ecr 0,sackOK,eol], length 0
	0x0000:  4500 0040 0000 4000 4006 0000 7f00 0001
	0x0010:  7f00 0001 f81b 22b8 13d5 6b36 0000 0000
	0x0020:  b002 ffff fe34 0000 0204 3fd8 0103 0306
	0x0030:  0101 080a 5dba f594 0000 0000 0402 0000

过程:客户端(通过执行connect函数)向服务器端发送一个SYN包,请求一个主动打开。该包携带客户端为这个连接请求而设定的随机数(seq=332753718,hex(seq)=13d56b36)作为消息序列号。暂且称此次数据包的seq为s1

意义:确认客户端发送能力正常

第二次握手(server -> client)

IP 127.0.0.1.8888 > 127.0.0.1.63515: Flags [S.], seq 1886023911, ack 332753719, win 65535, options [mss 16344,nop,wscale 6,nop,nop,TS val 1572533652 ecr 1572533652,sackOK,eol], length 0
	0x0000:  4500 0040 0000 4000 4006 0000 7f00 0001
	0x0010:  7f00 0001 22b8 f81b 706a 70e7 13d5 6b37
	0x0020:  b012 ffff fe34 0000 0204 3fd8 0103 0306
	0x0030:  0101 080a 5dba f594 5dba f594 0402 0000

过程:服务器端收到一个合法的SYN包后,把该包放入SYN队列中;回送一个SYN/ACK。ACK的确认码应为第一次握手的s1+1,SYN/ACK包本身携带一个随机产生的seq。暂且称此次数据包的ACK为a1,暂且称此次数据包的seq为s2

意义:服务端的接收、发送能力正常

第三次 握手(client -> server, server -> client)

IP 127.0.0.1.63515 > 127.0.0.1.8888: Flags [.], ack 1, win 6379, options [nop,nop,TS val 1572533652 ecr 1572533652], length 0
	0x0000:  4500 0034 0000 4000 4006 0000 7f00 0001
	0x0010:  7f00 0001 f81b 22b8 13d5 6b37 706a 70e8
	0x0020:  8010 18eb fe28 0000 0101 080a 5dba f594
	0x0030:  5dba f594
IP 127.0.0.1.8888 > 127.0.0.1.63515: Flags [.], ack 1, win 6379, options [nop,nop,TS val 1572533652 ecr 1572533652], length 0
	0x0000:  4500 0034 0000 4000 4006 0000 7f00 0001
	0x0010:  7f00 0001 22b8 f81b 706a 70e8 13d5 6b37
	0x0020:  8010 18eb fe28 0000 0101 080a 5dba f594
	0x0030:  5dba f594

过程:客户端收到SYN/ACK包后,发送一个ACK包,该包的seq被设定为a1+1,而ACK的确认码则为s2+1。然后客户端的connect函数成功返回。当服务器端收到这个ACK包的时候,把请求帧从SYN队列中移出,放至ACCEPT队列中;这时accept函数如果处于阻塞状态,可以被唤醒,从ACCEPT队列中取出ACK包,重新创建一个新的用于双向通信的sockfd,并返回。

意义: 客户端接收能力正常

我自己感觉虽然是3次握手,但是由于tcp协议的对称性,即有发送就会有响应,所以真实是4次?

数据传输

IP 127.0.0.1.63515 > 127.0.0.1.8888: Flags [P.], seq 1:1060, ack 1, win 6379, options [nop,nop,TS val 1572533652 ecr 1572533652], length 1059
	0x0000:  4500 0457 0000 4000 4006 0000 7f00 0001  E..W..@.@.......
	0x0010:  7f00 0001 f81b 22b8 13d5 6b37 706a 70e8  ......"...k7pjp.
	0x0020:  8018 18eb 024c 0000 0101 080a 5dba f594  .....L......]...
	0x0030:  5dba f594 504f 5354 202f 6261 7365 2f6c  ]...POST./base/l
	0x0040:  6f67 696e 2048 5454 502f 312e 310d 0a48  ogin.HTTP/1.1..H
	0x0050:  6f73 743a 2031 3237 2e30 2e30 2e31 3a38  ost:.127.0.0.1:8
	0x0060:  3838 380d 0a43 6f6e 6e65 6374 696f 6e3a  888..Connection:
	0x0070:  206b 6565 702d 616c 6976 650d 0a43 6f6e  .keep-alive..Con
	0x0080:  7465 6e74 2d4c 656e 6774 683a 2039 380d  tent-Length:.98.
	0x0090:  0a61 6363 6570 743a 2061 7070 6c69 6361  .accept:.applica
	0x00a0:  7469 6f6e 2f6a 736f 6e0d 0a55 7365 722d  tion/json..User-
	0x00b0:  4167 656e 743a 204d 6f7a 696c 6c61 2f35  Agent:.Mozilla/5
	0x00c0:  2e30 2028 4d61 6369 6e74 6f73 683b 2049  .0.(Macintosh;.I
	0x00d0:  6e74 656c 204d 6163 204f 5320 5820 3131  ntel.Mac.OS.X.11
	0x00e0:  5f31 5f30 2920 4170 706c 6557 6562 4b69  _1_0).AppleWebKi
	0x00f0:  742f 3533 372e 3336 2028 4b48 544d 4c2c  t/537.36.(KHTML,
	0x0100:  206c 696b 6520 4765 636b 6f29 2043 6872  .like.Gecko).Chr
	0x0110:  6f6d 652f 3837 2e30 2e34 3238 302e 3134  ome/87.0.4280.14
	0x0120:  3120 5361 6661 7269 2f35 3337 2e33 360d  1.Safari/537.36.
	0x0130:  0a43 6f6e 7465 6e74 2d54 7970 653a 2061  .Content-Type:.a
	0x0140:  7070 6c69 6361 7469 6f6e 2f6a 736f 6e0d  pplication/json.
	0x0150:  0a4f 7269 6769 6e3a 2068 7474 703a 2f2f  .Origin:.http://
	0x0160:  3132 372e 302e 302e 313a 3838 3838 0d0a  127.0.0.1:8888..
	0x0170:  5365 632d 4665 7463 682d 5369 7465 3a20  Sec-Fetch-Site:.
	0x0180:  7361 6d65 2d6f 7269 6769 6e0d 0a53 6563  same-origin..Sec
	0x0190:  2d46 6574 6368 2d4d 6f64 653a 2063 6f72  -Fetch-Mode:.cor
	0x01a0:  730d 0a53 6563 2d46 6574 6368 2d44 6573  s..Sec-Fetch-Des
	0x01b0:  743a 2065 6d70 7479 0d0a 5265 6665 7265  t:.empty..Refere
	0x01c0:  723a 2068 7474 703a 2f2f 3132 372e 302e  r:.http://127.0.
	0x01d0:  302e 313a 3838 3838 2f73 7761 6767 6572  0.1:8888/swagger
	0x01e0:  2f69 6e64 6578 2e68 746d 6c0d 0a41 6363  /index.html..Acc
	0x01f0:  6570 742d 456e 636f 6469 6e67 3a20 677a  ept-Encoding:.gz
	0x0200:  6970 2c20 6465 666c 6174 652c 2062 720d  ip,.deflate,.br.
	0x0210:  0a41 6363 6570 742d 4c61 6e67 7561 6765  .Accept-Language
	0x0220:  3a20 7a68 2d43 4e2c 7a68 3b71 3d30 2e39  :.zh-CN,zh;q=0.9
	0x0230:  0d0a 436f 6f6b 6965 3a20 5f67 613d 4741  ..Cookie:._ga=GA
	0x0240:  312e 312e 3131 3434 3731 3235 3531 2e31  1.1.1144712551.1
	0x0250:  3630 3939 3430 3830 323b 205f 686f 6d65  609940802;._home
	0x0260:  6c61 6e64 5f73 6573 7369 6f6e 3d73 4962  land_session=sIb
	0x0270:  7a4b 2532 4243 776b 4525 3242 5954 3978  zK%2BCwkE%2BYT9x
	0x0280:  425a 3675 5041 7877 4641 4b46 4869 7732  BZ6uPAxwFAKFHiw2
	0x0290:  6861 7150 3951 796b 5968 7371 7647 4d70  haqP9QykYhsqvGMp
	0x02a0:  3033 5872 4470 5330 6a38 4b4f 6535 6c36  03XrDpS0j8KOe5l6
	0x02b0:  6e48 2532 4654 4770 5151 324e 6157 7154  nH%2FTGpQQ2NaWqT
	0x02c0:  654a 4f71 4944 6a6b 3272 537a 347a 4e54  eJOqIDjk2rSz4zNT
	0x02d0:  6c63 586a 5843 4a64 3537 4b57 6642 4142  lcXjXCJd57KWfBAB
	0x02e0:  7861 6463 5657 3070 586f 4177 3933 7444  xadcVW0pXoAw93tD
	0x02f0:  5331 7a51 6663 6458 6d4d 3869 7263 3337  S1zQfcdXmM8irc37
	0x0300:  7834 6c77 3179 514d 635a 6c33 4771 616e  x4lw1yQMcZl3Gqan
	0x0310:  4462 5639 5a58 6464 7375 6725 3246 7452  DbV9ZXddsug%2FtR
	0x0320:  5655 4766 5953 3550 3874 6d44 5161 3362  VUGfYS5P8tmDQa3b
	0x0330:  4968 4e7a 6a25 3242 6555 506a 6866 3725  IhNzj%2BeUPjhf7%
	0x0340:  3246 7671 5446 4353 4c31 6a72 3268 4146  2FvqTFCSL1jr2hAF
	0x0350:  2532 4249 4225 3242 5255 4834 5551 6453  %2BIB%2BRUH4UQdS
	0x0360:  6b76 6750 6f7a 6d74 6e48 6172 6241 4f6b  kvgPozmtnHarbAOk
	0x0370:  4e6f 5250 2532 4676 596a 5376 3261 4f37  NoRP%2FvYjSv2aO7
	0x0380:  506a 7358 7178 6248 5932 4a44 3866 5a51  PjsXqxbHY2JD8fZQ
	0x0390:  6453 6c45 6d70 577a 4c41 5844 6745 7665  dSlEmpWzLAXDgEve
	0x03a0:  3536 5755 4f69 6869 3559 6876 3564 4b76  56WUOihi5Yhv5dKv
	0x03b0:  6171 7047 6d37 5736 534f 716d 436f 2533  aqpGm7W6SOqmCo%3
	0x03c0:  442d 2d4d 5271 6745 4f6b 3343 4e45 4543  D--MRqgEOk3CNEEC
	0x03d0:  5a6e 462d 2d72 3166 7154 3148 7830 5764  ZnF--r1fqT1Hx0Wd
	0x03e0:  796e 7444 3357 3744 5951 6725 3344 2533  yntD3W7DYQg%3D%3
	0x03f0:  440d 0a0d 0a7b 0a20 2022 6361 7074 6368  D....{..."captch
	0x0400:  6122 3a20 2273 7472 696e 6722 2c0a 2020  a":."string",...
	0x0410:  2263 6170 7463 6861 4964 223a 2022 7374  "captchaId":."st
	0x0420:  7269 6e67 222c 0a20 2022 7061 7373 776f  ring",..."passwo
	0x0430:  7264 223a 2022 7374 7269 6e67 222c 0a20  rd":."string",..
	0x0440:  2022 7573 6572 6e61 6d65 223a 2022 7374  ."username":."st
	0x0450:  7269 6e67 220a 7d                        ring".}
IP 127.0.0.1.8888 > 127.0.0.1.63515: Flags [.], ack 1060, win 6363, options [nop,nop,TS val 1572533652 ecr 1572533652], length 0
	0x0000:  4500 0034 0000 4000 4006 0000 7f00 0001  E..4..@.@.......
	0x0010:  7f00 0001 22b8 f81b 706a 70e8 13d5 6f5a  ...."...pjp...oZ
	0x0020:  8010 18db fe28 0000 0101 080a 5dba f594  .....(......]...
	0x0030:  5dba f594
IP 127.0.0.1.8888 > 127.0.0.1.63515: Flags [P.], seq 1:550, ack 1060, win 6363, options [nop,nop,TS val 1572533671 ecr 1572533652], length 549
	0x0000:  4500 0259 0000 4000 4006 0000 7f00 0001  E..Y..@.@.......
	0x0010:  7f00 0001 22b8 f81b 706a 70e8 13d5 6f5a  ...."...pjp...oZ
	0x0020:  8018 18db 004e 0000 0101 080a 5dba f5a7  .....N......]...
	0x0030:  5dba f594 4854 5450 2f31 2e31 2032 3030  ]...HTTP/1.1.200
	0x0040:  204f 4b0d 0a41 6363 6573 732d 436f 6e74  .OK..Access-Cont
	0x0050:  726f 6c2d 416c 6c6f 772d 4372 6564 656e  rol-Allow-Creden
	0x0060:  7469 616c 733a 2074 7275 650d 0a41 6363  tials:.true..Acc
	0x0070:  6573 732d 436f 6e74 726f 6c2d 416c 6c6f  ess-Control-Allo
	0x0080:  772d 4865 6164 6572 733a 2043 6f6e 7465  w-Headers:.Conte
	0x0090:  6e74 2d54 7970 652c 4163 6365 7373 546f  nt-Type,AccessTo
	0x00a0:  6b65 6e2c 582d 4353 5246 2d54 6f6b 656e  ken,X-CSRF-Token
	0x00b0:  2c20 4175 7468 6f72 697a 6174 696f 6e2c  ,.Authorization,
	0x00c0:  2054 6f6b 656e 2c58 2d54 6f6b 656e 2c58  .Token,X-Token,X
	0x00d0:  2d55 7365 722d 4964 0d0a 4163 6365 7373  -User-Id..Access
	0x00e0:  2d43 6f6e 7472 6f6c 2d41 6c6c 6f77 2d4d  -Control-Allow-M
	0x00f0:  6574 686f 6473 3a20 504f 5354 2c20 4745  ethods:.POST,.GE
	0x0100:  542c 204f 5054 494f 4e53 2c44 454c 4554  T,.OPTIONS,DELET
	0x0110:  452c 5055 540d 0a41 6363 6573 732d 436f  E,PUT..Access-Co
	0x0120:  6e74 726f 6c2d 416c 6c6f 772d 4f72 6967  ntrol-Allow-Orig
	0x0130:  696e 3a20 6874 7470 3a2f 2f31 3237 2e30  in:.http://127.0
	0x0140:  2e30 2e31 3a38 3838 380d 0a41 6363 6573  .0.1:8888..Acces
	0x0150:  732d 436f 6e74 726f 6c2d 4578 706f 7365  s-Control-Expose
	0x0160:  2d48 6561 6465 7273 3a20 436f 6e74 656e  -Headers:.Conten
	0x0170:  742d 4c65 6e67 7468 2c20 4163 6365 7373  t-Length,.Access
	0x0180:  2d43 6f6e 7472 6f6c 2d41 6c6c 6f77 2d4f  -Control-Allow-O
	0x0190:  7269 6769 6e2c 2041 6363 6573 732d 436f  rigin,.Access-Co
	0x01a0:  6e74 726f 6c2d 416c 6c6f 772d 4865 6164  ntrol-Allow-Head
	0x01b0:  6572 732c 2043 6f6e 7465 6e74 2d54 7970  ers,.Content-Typ
	0x01c0:  650d 0a43 6f6e 7465 6e74 2d54 7970 653a  e..Content-Type:
	0x01d0:  2061 7070 6c69 6361 7469 6f6e 2f6a 736f  .application/jso
	0x01e0:  6e3b 2063 6861 7273 6574 3d75 7466 2d38  n;.charset=utf-8
	0x01f0:  0d0a 4461 7465 3a20 5361 742c 2031 3620  ..Date:.Sat,.16.
	0x0200:  4a61 6e20 3230 3231 2030 393a 3336 3a34  Jan.2021.09:36:4
	0x0210:  3420 474d 540d 0a43 6f6e 7465 6e74 2d4c  4.GMT..Content-L
	0x0220:  656e 6774 683a 2034 340d 0a0d 0a7b 2263  ength:.44....{"c
	0x0230:  6f64 6522 3a37 2c22 6461 7461 223a 7b7d  ode":7,"data":{}
	0x0240:  2c22 6d73 6722 3a22 e9aa 8ce8 af81 e7a0  ,"msg":"........
	0x0250:  81e9 9499 e8af af22 7d                   ......."}
IP 127.0.0.1.63515 > 127.0.0.1.8888: Flags [.], ack 550, win 6371, options [nop,nop,TS val 1572533671 ecr 1572533671], length 0
	0x0000:  4500 0034 0000 4000 4006 0000 7f00 0001  E..4..@.@.......
	0x0010:  7f00 0001 f81b 22b8 13d5 6f5a 706a 730d  ......"...oZpjs.
	0x0020:  8010 18e3 fe28 0000 0101 080a 5dba f5a7  .....(......]...
	0x0030:  5dba f5a7

可以看出http协议中的get,post…本质上是没有区别的,请求数据放在query,header,body本质是没有区别的,只是要用合适方式去做合适的事

关闭连接

IP 127.0.0.1.8888 > 127.0.0.1.63515: Flags [F.], seq 550, ack 1060, win 6363, options [nop,nop,TS val 1572533681 ecr 1572533671], length 0
	0x0000:  4500 0034 0000 4000 4006 0000 7f00 0001  E..4..@.@.......
	0x0010:  7f00 0001 22b8 f81b 706a 730d 13d5 6f5a  ...."...pjs...oZ
	0x0020:  8011 18db fe28 0000 0101 080a 5dba f5b1  .....(......]...
	0x0030:  5dba f5a7                                ]...
IP 127.0.0.1.63515 > 127.0.0.1.8888: Flags [.], ack 551, win 6371, options [nop,nop,TS val 1572533681 ecr 1572533681], length 0
	0x0000:  4500 0034 0000 4000 4006 0000 7f00 0001  E..4..@.@.......
	0x0010:  7f00 0001 f81b 22b8 13d5 6f5a 706a 730e  ......"...oZpjs.
	0x0020:  8010 18e3 fe28 0000 0101 080a 5dba f5b1  .....(......]...
	0x0030:  5dba f5b1                                ]...
IP 127.0.0.1.63515 > 127.0.0.1.8888: Flags [.], ack 551, win 6371, length 0
	0x0000:  4500 0028 6b78 0000 4006 0000 7f00 0001  E..(kx..@.......
	0x0010:  7f00 0001 f81b 22b8 13d5 6f59 706a 730e  ......"...oYpjs.
	0x0020:  5010 18e3 fe1c 0000                      P.......
IP 127.0.0.1.8888 > 127.0.0.1.63515: Flags [.], ack 1060, win 6363, options [nop,nop,TS val 1572578966 ecr 1572533681], length 0
	0x0000:  4500 0034 0000 4000 4006 0000 7f00 0001  E..4..@.@.......
	0x0010:  7f00 0001 22b8 f81b 706a 730e 13d5 6f5a  ...."...pjs...oZ
	0x0020:  8010 18db fe28 0000 0101 080a 5dbb a696  .....(......]...
	0x0030:  5dba f5b1                                ]...
IP 127.0.0.1.63515 > 127.0.0.1.8888: Flags [F.], seq 1060, ack 551, win 6371, options [nop,nop,TS val 1572607233 ecr 1572578966], length 0
	0x0000:  4500 0034 0000 4000 4006 0000 7f00 0001  E..4..@.@.......
	0x0010:  7f00 0001 f81b 22b8 13d5 6f5a 706a 730e  ......"...oZpjs.
	0x0020:  8011 18e3 fe28 0000 0101 080a 5dbc 1501  .....(......]...
	0x0030:  5dbb a696                                ]...
IP 127.0.0.1.8888 > 127.0.0.1.63515: Flags [.], ack 1061, win 6363, options [nop,nop,TS val 1572607233 ecr 1572607233], length 0
	0x0000:  4500 0034 0000 4000 4006 0000 7f00 0001  E..4..@.@.......
	0x0010:  7f00 0001 22b8 f81b 706a 730e 13d5 6f5b  ...."...pjs...o[
	0x0020:  8010 18db fe28 0000 0101 080a 5dbc 1501  .....(......]...
	0x0030:  5dbc 1501                                ]...

连接终止使用了四路握手过程(或称四次握手,four-way handshake),在这个过程中连接的每一侧都独立地被终止。当一个端点要停止它这一侧的连接,就向对侧发送FIN,对侧回复ACK表示确认。因此,拆掉一侧的连接过程需要一对FIN和ACK,分别由两侧端点发出。

首先发出FIN的一侧,如果给对侧的FIN响应了ACK,那么就会超时等待2*MSL时间,然后关闭连接。在这段超时等待时间内,本地的端口不能被新连接使用;避免延时的包的到达与随后的新连接相混淆。RFC793定义了MSL为2分钟,Linux设置成了30s。参数tcp_max_tw_buckets控制并发的TIME_WAIT的数量,默认值是180000,如果超限,那么,系统会把多的TIME_WAIT状态的连接给destory掉,然后在日志里打一个警告(如:time wait bucket table overflow)

连接可以工作在TCP半开状态。即一侧关闭了连接,不再发送数据;但另一侧没有关闭连接,仍可以发送数据。已关闭的一侧仍然应接收数据,直至对侧也关闭了连接。

也可以通过测三次握手关闭连接。主机A发出FIN,主机B回复FIN & ACK,然后主机A回复ACK.

https://zh.wikipedia.org/wiki/%E4%BC%A0%E8%BE%93%E6%8E%A7%E5%88%B6%E5%8D%8F%E8%AE%AE

tcp抓包工具:tcpdump