关于TCP的一些零散知识
2016-04-11 16:07
453 查看
一、 Socket能连接的最大端口号是多少?
答案是65536,也就是2的16次方。那么这个数值是怎么算出来的呢?看过下面的图,你就明白了
图1
上图是TCP首部的结构图,一个TCP首部固定部分只有20字节大小,前四个字节用来存储源端口和目的端口,各占两个字节,两个字节最大也就是2的16次方嘛。不过如果你在使用Socket时,端口号设置成了66000,也是可以连接的,但这不表明端口号真的超过了65536,仅仅是因为端口号大小“溢出”后,变成了66000-65536 = 464,真实打开的端口号是464
二、 TCP的三次握手到底是咋回事?
先看下面的两个小图
图2 图3
图2里,有6个标识位,都只占1位,图3里,是序号和确认号,说道序号,很多技术帖子里说是随机生成的,这是不准确的,当一端为建立连接而发送一个SYN包时,会选择一个初始序号--ISN,ISN随时间而变化,RFC 793 指出ISN可看作是一个32比特的计数器,每4ms加1,对这个序号,我们不必过多关心。
第一次握手:
方向: 数据由客户端发往服务端
标识位状态: SYN位是1,其他5个标识位是0
序号: 假设初始为J
确认号: 第一次握手时无效,不用管
这个,就是大家常说的SYN包
第二次握手:
服务端发现收到的包里,SYN标识位是1,他明白了,这个客户端想要和我建立连接,现在进行应答
方向: 服务端发往客户端
标识位状态,SYN,ACK是1,其他4个标识位是0
序号: 假设初始为K
确认号: J + 1 ,表示服务端已经收到了第一次握手时由客户端发来的SYN包
第三次握手:
客户端发现,收到的包里,SYN,ACK,都是1,那看来是服务端已经知道我想和他建立起连接了,接下来就确认一下,收到的包里,确认号是不是等于我第一次发给他的包里的序号+1 ,上述条件成立时,才会发一个ACK包给服务端
方向: 客户端发往服务端
标识位状态: ACK是1,其他5个标识位是0
序号: K
确认号: K+1 ,表示客户端已经收到了第二次握手时由服务端发来的ACK+SYN包
服务端收到第三次握手时由客户端发来的ACK包后,会检查确认号是不是等于自己第二次握手时发给客户端的ACK+SYN包里的序号+1,如果是,那么连接就建立起来了。这里要特殊说明的是,如果用wireshark抓包,你会发现,三次握手时,确认号都是从0开始的,但上面已经讲到,确认号是随机生成的,之所以会有这样的矛盾,那是因为wireshark考虑到用户的使用感受,确认号是进过处理的,显示出来的,是相对于随机数的偏移量,这样方便大家查看。
三、 TCP四次挥手
建立连接的时候,进行三次握手,断开连接的时候,进行四次挥手。
以客户端主动断开连接为例:
第一阶段:
第一次挥手,客户端发送一个FIN包(FIN标识位是1),序号为I,这是在告诉服务端,我打算关闭写通道了
第二次挥手,服务端收到第一步中发出的FIN包,关闭自己的读通道,发送一个ACK包,序号为I+1 ,表明我已经关闭读通道了,现在你可以关闭写通道了
客户端在收到了服务端发来的ACK包以后,关闭写通道,至此,四次挥手的第一阶段完成了。
第二次挥手中,服务端收到FIN包后,不会立马关闭自己的写通道,因为此时可能还有一些数据仍然在发送中,现在,服务端只是关闭读通道,此时,客户端仍然可以接收数据,服务端也可以发送数据
第二阶段:
第三次挥手,服务端写完了数据,发送一个FIN包,序号为J,告诉客户端,我打算关闭写通道了
第四次挥手,客户端收到第三次挥手中发来的FIN包,关闭自己的读通道,发送一个ACK包,序号为J+1,表明我已经关闭读通道了,现在,你可以关闭写通道了
服务端收到ACK包后,关闭自己的写通道
TCP是全双工的,因此每个方向必须单独关闭,你可能会注意到,建立连接的时候,是三次握手,而关闭的时候要进行四次挥手呢。建立连接的第二次握手过程中,服务端返回的是一个ACK+SYN包,也就是说确认包和SYN包是结合一起发回去的(syn和ack同时设置为1),因为实在是没必要分两次发送,而断开连接时,第二次挥手过程中,服务端只发回去一个ACK包,因为此时,仍然有些数据还没有发送给客户端,因此还不能发给客户端FIN包,一定要等到所有数据都发送结束了才能发送FIN包,就是这个原因,导致断开连接时是四次挥手。
四、 一个TCP分组最大可以发送多大的数
MSS,即Max Segment Size,这个东西标识了一个TCP分组能装载的最大数据,如果使用wireshark抓包,会发现,建立连接的两端,在最初发送自己的SYN包时,都会说明自己的MSS,此后,双方发送TCP分组数据时,就以最小的为数据大小上限进行发送。以太网数据帧最大是1518字节,其中有14个字节的帧头和4个字节的校验,这样还剩下1500个字节可用于发送数据。IP头最小20字节,TCP头最小20字节,这样,还剩下1460个字节可用于装载数据。但实际抓包发现,MSS可能会是1448,一个解释是TCP头里有12个字节的时间戳。图1中,有一段是选项,变长的,如果选项的长度不够,还要填充,确保TCP头部的长度是4个字节的倍数。TCP头部,有一段数据偏移,这部分有4位,最大为1111(15),这个数值的意思,TCP有多少个4字节。都是1,也就是15,表示TCP头部长度为60字节,因此,TCP头部最大为60字节。
答案是65536,也就是2的16次方。那么这个数值是怎么算出来的呢?看过下面的图,你就明白了
图1
上图是TCP首部的结构图,一个TCP首部固定部分只有20字节大小,前四个字节用来存储源端口和目的端口,各占两个字节,两个字节最大也就是2的16次方嘛。不过如果你在使用Socket时,端口号设置成了66000,也是可以连接的,但这不表明端口号真的超过了65536,仅仅是因为端口号大小“溢出”后,变成了66000-65536 = 464,真实打开的端口号是464
二、 TCP的三次握手到底是咋回事?
先看下面的两个小图
图2 图3
图2里,有6个标识位,都只占1位,图3里,是序号和确认号,说道序号,很多技术帖子里说是随机生成的,这是不准确的,当一端为建立连接而发送一个SYN包时,会选择一个初始序号--ISN,ISN随时间而变化,RFC 793 指出ISN可看作是一个32比特的计数器,每4ms加1,对这个序号,我们不必过多关心。
第一次握手:
方向: 数据由客户端发往服务端
标识位状态: SYN位是1,其他5个标识位是0
序号: 假设初始为J
确认号: 第一次握手时无效,不用管
这个,就是大家常说的SYN包
第二次握手:
服务端发现收到的包里,SYN标识位是1,他明白了,这个客户端想要和我建立连接,现在进行应答
方向: 服务端发往客户端
标识位状态,SYN,ACK是1,其他4个标识位是0
序号: 假设初始为K
确认号: J + 1 ,表示服务端已经收到了第一次握手时由客户端发来的SYN包
第三次握手:
客户端发现,收到的包里,SYN,ACK,都是1,那看来是服务端已经知道我想和他建立起连接了,接下来就确认一下,收到的包里,确认号是不是等于我第一次发给他的包里的序号+1 ,上述条件成立时,才会发一个ACK包给服务端
方向: 客户端发往服务端
标识位状态: ACK是1,其他5个标识位是0
序号: K
确认号: K+1 ,表示客户端已经收到了第二次握手时由服务端发来的ACK+SYN包
服务端收到第三次握手时由客户端发来的ACK包后,会检查确认号是不是等于自己第二次握手时发给客户端的ACK+SYN包里的序号+1,如果是,那么连接就建立起来了。这里要特殊说明的是,如果用wireshark抓包,你会发现,三次握手时,确认号都是从0开始的,但上面已经讲到,确认号是随机生成的,之所以会有这样的矛盾,那是因为wireshark考虑到用户的使用感受,确认号是进过处理的,显示出来的,是相对于随机数的偏移量,这样方便大家查看。
三、 TCP四次挥手
建立连接的时候,进行三次握手,断开连接的时候,进行四次挥手。
以客户端主动断开连接为例:
第一阶段:
第一次挥手,客户端发送一个FIN包(FIN标识位是1),序号为I,这是在告诉服务端,我打算关闭写通道了
第二次挥手,服务端收到第一步中发出的FIN包,关闭自己的读通道,发送一个ACK包,序号为I+1 ,表明我已经关闭读通道了,现在你可以关闭写通道了
客户端在收到了服务端发来的ACK包以后,关闭写通道,至此,四次挥手的第一阶段完成了。
第二次挥手中,服务端收到FIN包后,不会立马关闭自己的写通道,因为此时可能还有一些数据仍然在发送中,现在,服务端只是关闭读通道,此时,客户端仍然可以接收数据,服务端也可以发送数据
第二阶段:
第三次挥手,服务端写完了数据,发送一个FIN包,序号为J,告诉客户端,我打算关闭写通道了
第四次挥手,客户端收到第三次挥手中发来的FIN包,关闭自己的读通道,发送一个ACK包,序号为J+1,表明我已经关闭读通道了,现在,你可以关闭写通道了
服务端收到ACK包后,关闭自己的写通道
TCP是全双工的,因此每个方向必须单独关闭,你可能会注意到,建立连接的时候,是三次握手,而关闭的时候要进行四次挥手呢。建立连接的第二次握手过程中,服务端返回的是一个ACK+SYN包,也就是说确认包和SYN包是结合一起发回去的(syn和ack同时设置为1),因为实在是没必要分两次发送,而断开连接时,第二次挥手过程中,服务端只发回去一个ACK包,因为此时,仍然有些数据还没有发送给客户端,因此还不能发给客户端FIN包,一定要等到所有数据都发送结束了才能发送FIN包,就是这个原因,导致断开连接时是四次挥手。
四、 一个TCP分组最大可以发送多大的数
MSS,即Max Segment Size,这个东西标识了一个TCP分组能装载的最大数据,如果使用wireshark抓包,会发现,建立连接的两端,在最初发送自己的SYN包时,都会说明自己的MSS,此后,双方发送TCP分组数据时,就以最小的为数据大小上限进行发送。以太网数据帧最大是1518字节,其中有14个字节的帧头和4个字节的校验,这样还剩下1500个字节可用于发送数据。IP头最小20字节,TCP头最小20字节,这样,还剩下1460个字节可用于装载数据。但实际抓包发现,MSS可能会是1448,一个解释是TCP头里有12个字节的时间戳。图1中,有一段是选项,变长的,如果选项的长度不够,还要填充,确保TCP头部的长度是4个字节的倍数。TCP头部,有一段数据偏移,这部分有4位,最大为1111(15),这个数值的意思,TCP有多少个4字节。都是1,也就是15,表示TCP头部长度为60字节,因此,TCP头部最大为60字节。
相关文章推荐
- 浏览器 HTTP 协议缓存机制详解
- 安卓使用http下载文件
- ZStack禁止入网
- android中判断网络连接是否可用
- HttpPost实现Request Payload
- 用webmagic实现的网络爬虫
- zz: virsual studio等AP无法访问网络映射驱动器(netmap drive)的解决办法
- HTTP基础与Android之——使用HttpClient和HttpURLConnection
- HTTP 500.22 错误解决
- iOS学习笔记13-网络(二)NSURLSession
- iOS学习笔记14-网络(三)WebView
- iOS学习笔记12-网络(一)NSURLConnection
- 获取网络日期时间,并设置本机系统日期时间
- 大端小端 主机字节序 网络字节序
- 网络爬虫-python-爬取天涯求职贴
- 关于HTTP header
- 使用Vitamio打造自己的Android万能播放器(12)—— 播放网络视频缓冲处理
- PID控制器的应用:控制网络爬虫抓取速度
- HTTP POST请求报文格式分析与Java实现文件上传
- JavaScript-XMLHttpRequest实例