1、源端口号:发送方端口号
2、目的端口号:接收方端口号
3、序列号:报文段的数据的第一个字节的序号
3、确认序号:期望收到对方下一个报文段的第一个数据字节的序号
4、首部长度(数据偏移):TCP报文段的数据起始距离TCP报文段的起始处有多远,即首部长度
6、保留:保留不用是置为0
7、紧急URG:此置为 1 ,紧急指针字段才有效,它告诉系统此报文段中有紧急数据,应尽快传送
8、确认位ACK:此置为 1,确认号字段才有效,TCP规定,在连接建立后所有传达的报文段都必须把 ACK 置 1
9、推送位PSH:此置为 1,即发送方,希望接收方接收缓冲区的数据,即TCP使用推送(PUSH)操作,接收方不再等整个缓冲区填满后再交付
10、复位RST:用于复位相应的TCP连接
11、同步SYN:仅在三次握手建立TCP连接时有效,当SYN = 1 且 ACK = 0,表明 请求连接报文段,SYN = 1 且 ACK = 0,同意建立连接报文段
12、终止FIN:用来释放连接,FIN = 1,表明此报文段的数据发送已经发送完毕,并要求释放连接
13、窗口大小:指发送本报文段的一方的接受窗口(而不是自己的发送窗口),最大为65535字节。
14、校验和:校验字段检验的范围(包括首部和数据两部分),计算校验和时需要加上 12 字节的伪头部
15、紧急指针:仅在 URG = 1时才有意义,它代表本报文段中的紧急数据的字节数(紧急数据结束后就是普通数据),即指出紧急数据在报文末尾的位置,(注意:及时窗口为0 时也可以发送紧急数据)
16、选项:长度可变,最长可达 40 字节,当没有使用选项时,TCP首部长度是 20 字节
wireshark抓包
Transmission Control Protocol, Src Port: http (80), Dst Port: 60575 (60575), Seq: 624361, Ack: 1, Len: 1452
Source Port: http (80) //源端口号
Destination Port: 60575 (60575) //目的端口号
[Stream index: 0]
[TCP Segment Len: 1452]
Sequence number: 624361 (relative sequence number) //32位序列号
[Next sequence number: 625813 (relative sequence number)]
Acknowledgment number: 1 (relative ack number) //32位确认序列号,即发送端希望收到的序列号
0101 .... = Header Length: 20 bytes (5) //4位首部长度
Flags: 0x010 (ACK) //标志位 ACK置1
000. .... .... = Reserved: Not set //保留位
...0 .... .... = Nonce: Not set //新增的
.... 0... .... = Congestion Window Reduced (CWR): Not set //新增的
.... .0.. .... = ECN-Echo: Not set //新增的
.... ..0. .... = Urgent: Not set
.... ...1 .... = Acknowledgment: Set
.... .... 0... = Push: Not set
.... .... .0.. = Reset: Not set
.... .... ..0. = Syn: Not set
.... .... ...0 = Fin: Not set
[TCP Flags: ·······A····]
Window size value: 240 //16位窗口大小(用于接收方的流量控制)
[Calculated window size: 240]
[Window size scaling factor: -1 (unknown)]
Checksum: 0xacb5 [unverified] //16位检验和
[Checksum Status: Unverified]
Urgent pointer: 0 //16位紧急指针
[SEQ/ACK analysis]
[Bytes in flight: 4356]
[Bytes sent since last PSH flag: 622908]
[Timestamps]
[Time since first frame in this TCP stream: 3.239693000 seconds]
[Time since previous frame in this TCP stream: 0.000001000 seconds]
TCP payload (1452 bytes) //TCP有效载荷
网络状态图
三次握手和四次挥手
为什么连接建立需要三次握手,而不是两次握手?
防止失效的连接请求报文段被服务端接收,从而产生错误.主要目的防止server端一直等待,浪费资源.
由于TCP连接是全双工的,因此每个方向都必须单独进行关闭.
因为当收到对方的FIN报文通知时,它仅仅表示对方没有数据发送给你了;但未必你所有的数据都全部发送给对方了,所以你可能还需要发送一些数据给对方,再发送FIN报文给对方来表示你同意现在可以关闭连接了,故这里的ACK报文和FIN报文多数情况下都是分开发送的,也就造成了4次挥手。
2MSL的作用:
等待2MSL时间主要目的是怕最后一个ACK包对方没收到,那么对方在超时后将重发第三次握手的FIN包,主动关闭端接到重发的FIN包后可以再发一个ACK应答包。在TIME_WAIT状态时两端的端口不能使用,要等到2MSL时间结束才可继续使用。当连接处于2MSL等待阶段时任何迟到的报文段都将被丢弃。不过在实际应用中可以通过设置SO_REUSEADDR选项达到不必等待2MSL时间结束再使用此端口。一般MSL设置为30s、1min等
connect函数由系统决定超时时间,一般是75s.
发送一个syn,若无响应的等待几秒再发送一个,连续好几次,等到75s仍不响应。
复位报文段
目的端口没有在使用,tcp连接会返回复位(RST),udp是icmp端口不可达。
异常终止一个连接,发送的是RST,而不是FIN.
延伸:异常关闭的优点:1.丢弃任何待发送的数据并立即发送RST复位报文段。2.RST接收方会区分另一端执行的是异常关闭还是正常关闭,应用程序需要提供异常关闭的处理。
半打开连接
一方已经关闭或异常终止连接而另一方却不知道。
解决办法:使用keepalive机制
同时打开
两个应用程序同时执行主动打开。这需要每一方使用对方熟知的端口作为本地端口。整个同时打开连接的过程需要交换4个报文段。同时每一端既是客户又是服务端。