TCP 基本特点:有连接、可靠传输、面向字节流、全双工
accept
建立联系才能处理clientSocket
对象的 InputStream
和 OutputStream
,再来去读写数据Socket
对象,既可以读,也可以写
而此处的可靠传输在代码层面感知不到,它是在系统内核完成了这里的工作TCP
最核心的资质就是“可靠传输”,不能做到 100%
送达,只能尽可能的是数据能到达对方方
互联网最初是用来防御核弹打击的,即使是遭受到了核弹打击,但是 A~B 之间的通信路径有很多很多条,不会全军覆没,所以仍然可以确保数据能正常传输
后发先至的解决方法,TCP 核心机制,感知对方是否收到,就是要靠对方告诉你一声“收到了”
TCP
是面向字节流的,是加上这里的编号并非是按照“第一条,第二条”这样的方式来编排的,而是按照“字节“,“第一个字节,第一百个字节”,这样来编排的TCP
的序号”,在应答报文中,针对之前收到的数据进行对应的编号,称为“TCP
的确认序号”之后,TCP 就可以针对接收方收到的信息,进行重新排序,确保应用程序 read 到的数据一定是和发送方的数据顺序是一致的
接收方这边调用 read 的时候如果没有数据,就会阻塞等待(前面回显服务器文章中写的是 scanner 读取,本质上就是调用 InputStream.read
)
1001-2000
这个数据到了,但是接收方不会让 read
接触阻塞,因为这个数据的起始部分还没到,2001-3000
到了之后也进行阻塞1-1000
这个数据到达之后,read
才会接触阻塞,才会读取到 1-1000
,1001-2000
,2001-3000
- 接收方这边,操作系统内核里面,有一段空间,作为“接收缓冲区”,收到的数据就会先在缓冲区中排队等待,直到开头的数据到了,应用程序才能真正读取到里面的数据前面接亲的例子:等婚车到了女方门口,因为头车还没来,所以不能直接开到新娘门口去接人丢包的原因有很多种:
N
个包,但现在是网络高峰期,这个路由器单位时间需要转发的包超过 N
个了,发不过来了发生丢包是完全随机,不可预测的,TCP
再怎么厉害,也不可能避免数据发生丢包。TCP
能做的是:感知到数据是否丢失,如果丢包,就重新再发一次
此时需要通过应答报文来区分
read
读出来的数据是唯一、不重复的,TCP 就会对这种情况进行处理——去重
- 接收方有一个“接收缓冲区”,收到的数据会先进入到缓冲区里,后续再督导数据,就会根据序号,在缓冲区中找到对应的位置(排序)。如果发现当前序号 1-1000 这个数据已经在缓冲区中存在了,就会直接把新收到的这个数据丢弃掉这里的时间不是固定不动的,而是动态变化的
发送方第一次重传,超时时间是 t1
,如果重传之后,仍然没有 ACK
,就会继续重传,第二次重传的超时时间是 t2
,t2>t1
TCP
不会再重传,就认为这个连接已经挂了TCP
就会单方面放弃连接(发送方释放掉之前接收方的相关信息,这个连接诶也就没了)确认应答和超时重传相互补充,共同构建了 TCP 的“可靠传输机制”
TCP
报头的长度
UDP
协议报头固定就是 8
个字节TCP
来说,报头长度是可变的
4 个比特位可表示的范围:0000~1111
——>0x0~0xF
——>0~15
0~60
字节)虽然现在不用,但是先把这个东西申请下来,以备不时之需。用于考虑未来的可扩展性
UDP
的教训,UDP
的报文长度字段,是没法扩展的TCP
需要新增属性或者谋和属性的长度不够用,就可以把保留位拿出来,进行使用TCP
的结构不需要发生太大的改变,这样的升级就会容易很多关于“可扩展性”也是属于编程的时候需要考虑到的一点,毕竟写的代码不可能写一份就能持续地使用。对代码做出调整,做出修改,是非常普遍、常见的情况
但是,
TCP 报头边长的主要原因。四个字节为一个单位
由于会出现“后发先至”的情况,所以需要通过编号,区分出数据的先后顺序
序号:表示的就是 TCP
数据报载荷中的第一个字节的序号,由于序号是连续递增,知道了第一个字节的序号,后续每个字节的序号也就知道了
0~42亿9千万
(0~4G
)TCP
是面向字节流的,所以一个 TCP
数据报和下一个 TCP
数据报携带的数据,是可以直接进行拼装的TCP
数据报来进行携带,这些 TCP
数据报彼此之间携带的载荷都是可以在接受方自动拼起来的
- 这样就不像 UDP
存在传输的上限,使用 UDP
传输大数据,就需要考虑调用这一次 send
操作,参数是否超过了 64KB
,超过了就不行
- 使用 TCP
的话就没关系,可以调用一次 write
,也可以调用多次 write
。无论怎么进行 write
,在网络传输和对端接收的角度来看是没有任何差别的
- 如果多次 write
,传输的总数据量超过上述的 4G
也没关系,这里的数据序号是可以再从 0 开始重新设置的确认序号的设定方式,和后发先至中发短信的例子,略有差别
TCP 的确认序号这里,填写的是 1001
,接收方收到的数据的最后一个字节序号的下一个序号
<1001
的序号的数据都收到了(TCP
序号是连续增长的)+1
的方式来填写ACK
)会设为 1
- 普通报文的 ACK
为 0
,应答报文的 ACK
为 1
- 如果是普通报文,序号是有效的,确认序号是无效的;如果是应答报文,序号和确认序号都是有效的
- 应答报文的序号是另一套编号体系,和传输数据的序号是不一样的
- 应答报文默认情况下是不携带数据的原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。