TCP_IP协议(传输层)笔记_传输层提供服务的对象-程序员宅基地

技术标签: Java  网络  linux  网络通信  

TCP/IP
应用层:程序员写代码的一层。HTTP、SSH、FTP、DNS
传输层:为了保证两端能够顺利的通讯。TCP、UDP
网络层:用来确定路线和路由选择。
数据链路层:相邻节点的数据接收和转换。

TCP两个对象(客户端和服务器端)
服务器:ServerSocket
客户端:Socket new Socket(IP,Port)

TCP读写数据的重要对象
读:BufferedReader socket.getInputStream 读取readLine()
写:BufferedWriter writer(“内容\n”)

TCP 与 UDP 的区别
UDP无连接;TCP是有连接的
UDP不稳定;TCP稳定
UDP面向数据报;TCP面向数据流
UDP只有接收缓存区,没有发送缓存区;TCP两个缓存区都有
UDP 和 TCP 使用场景不同,如果对稳定性要求比较高,应该使用TCP;如果对消息丢失不敏感,要求性能比较高,可以考虑使用UDP。

在这里插入图片描述
在这里插入图片描述



传输层

最大端口号:0-65535(2^16)

端口号分类
知名端口号:0-1023.。FTP:21;SSH:22;Telent:23;HTTP:80;HTTPS:443;Mysql:3306;Tomcat:8080
动态端口号:1024-65535

UDP协议

在这里插入图片描述
16位UDP长度 = UDP头部长度(8个字节) + 数据长度
UDP一个包的最大理论长度 = 2^16
16位源端口号:发送程序
16位目的端口号:找到接收程序
校验和:用来确定数据在传输过程中是否被篡改,用来判断数据的正确性。

如果UDP编程的时候数据大小大于64KB会怎样?
1.在应用层进行数据包的拆分和组合。
2.大于64KB不处理,交给TCP/IP协议取处理,它会在网络层进行分包和组包。

全双工与半双工
全:发送端或者是接收端,既能发送消息又能接收消息。
半:发送端只能发送消息,不能接收消息;接收端只能接收消息,不能发送消息。

基于UDP的应用层协议

  • NFS: 网络文件系统
  • TFTP: 简单文件传输协议
  • DHCP: 动态主机配置协议
  • BOOTP: 启动协议(用于无盘设备启动)
  • DNS: 域名解析协议

TCP 协议

在这里插入图片描述

4位首部长度
URG:0/1 表示是否为紧急指针。
ACK:是否确认应答消息
PSH:是否立即从缓冲区取走数据
RST:复位标识
SYN:同步序列号标识(TCP连接时候使用)
FIN :结束序列号标识 (TCP断开连接的时候)

TCP 8大特性

确认应答(ACK)

在这里插入图片描述

保障TCP稳定的核心机制

问题
发送消息丢失了
ACK丢失了
超时重发

Linux: 500ms

策略
发送不会以固定的频率发送,采用悲观策略,如果第一次失败,大概率第二次也会失败,TCP会以指数级超时时间增长的频率来发送消息。
如果经历了一定的重试次数,消息还没有得到应答,就会停止发送。

连接管理

3次握手 : 为了验证收、发两端的收、发能力。
4次挥手:为了确保发送端和接收端能够正常关闭。

在这里插入图片描述

服务端状态
[CLOSED -> LISTEN] :服务器端调用listen后进入LISTEN状态, 等待客户端连接;
[LISTEN -> SYN_RCVD] 一旦监听到连接请求(同步报文段), 就将该连接放入内核等待队列中, 并向客户端发送SYN确认报文;
[SYN_RCVD -> ESTABLISHED] 服务端一旦收到客户端的确认报文, 就进入ESTABLISHED状态, 可以进行读写数据了;
[ESTABLISHED -> CLOSE_WAIT] 当客户端主动关闭连接(调用close), 服务器会收到结束报文段, 服务器返回确认报文段并进入CLOSE_WAIT;
[CLOSE_WAIT -> LAST_ACK] 进入CLOSE_WAIT后说明服务器准备关闭连接(需要处理完之前的数据); 当服务器真正调用close关闭连接时, 会向客户端发送FIN, 此时服务器进入LAST_ACK状态, 等待最后一个ACK到来(这个ACK是客户端确认收到了FIN);
[LAST_ACK -> CLOSED] 服务器收到了对FIN的ACK, 彻底关闭连接;
客户端状态
[CLOSED -> SYN_SENT] 客户端调用connect, 发送同步报文段;
[SYN_SENT -> ESTABLISHED] connect调用成功, 则进入ESTABLISHED状态, 开始读写数据;
[ESTABLISHED -> FIN_WAIT_1] 客户端主动调用close时, 向服务器发送结束报文段, 同时进入FIN_WAIT_1;
[FIN_WAIT_1 -> FIN_WAIT_2] 客户端收到服务器对结束报文段的确认, 则进入FIN_WAIT_2, 开始等待服务器的结束报文段;
[FIN_WAIT_2 -> TIME_WAIT] 客户端收到服务器发来的结束报文段, 进入TIME_WAIT, 并发出LAST_ACK;
[TIME_WAIT -> CLOSED] 客户端要等待一个2MSL(Max Segment Life, 报文最大生存时间)的
时间, 才会进入CLOSED状态.

TIME_WAIT 2 MSL(最大超时时间)

2 MSL = ACK 最大超时时间(1 MSL) + 对方发送给它消息的一个最大等待时间(1 MSL)。
如果程序中存在大量的CLOSE_WAIT 说明程序中存在BUG,没有调用close()主动关闭连接。


滑动窗口

在这里插入图片描述
窗口大小指的是无需等待确认应答而可以继续发送数据的最大值. 上图的窗口大小就是4000
个字节(四个段);
发送前四个段的时候, 不需要等待任何ACK, 直接发送;
收到第一个ACK后, 滑动窗口向后移动, 继续发送第五个段的数据; 依次类推;
操作系统内核为了维护这个滑动窗口, 需要开辟 发送缓冲区 来记录当前还有哪些数据没有应搭,只有确认应答过的数据,才能从缓冲区删掉;
窗口越大, 则网络的吞吐率就越高;

情况一:数据包已经抵达,ACK被丢了
在这里插入图片描述
ACK = 6001的含义:并不是告诉主机A,已经成功收到5001~6000,而是告诉主机A,我成功接收了 0~6000.
ACK 返回的值是当前(主机B)接收缓冲区的下一个值(最大连续值)

情况二:数据包就直接丢了

在这里插入图片描述
当某一段报文段丢失之后, 发送端会一直收到 1001 这样的ACK, 就像是在提醒发送端 “我想要
的是 1001” 一样;
如果发送端主机连续三次收到了同样一个 “1001” 这样的应答, 就会将对应的数据 1001 -
2000 重新发送;
这个时候接收端收到了 1001 之后, 再次返回的ACK就是7001了(因为2001 - 7000)接收端其实
之前就已经收到了, 被放到了接收端操作系统内核的接收缓冲区中;
这种机制被称为 “高速重发控制”(也叫 “快重传”)

流量控制

以结果(接收缓冲区的大小)为导向进行数据的传递。
接收端处理数据的速度是有限的. 如果发送端发的太快, 导致接收端的缓冲区被打满, 这个时候如果发送端继续发送, 就会造成丢包, 继而引起丢包重传等等一系列连锁反应。因此TCP支持根据接收端的处理能力, 来决定发送端的发送速度. 这个机制就叫做流量控制。

  • 接收端将自己可以接收的缓冲区大小放入 TCP 首部中的 “窗口大小” 字段, 通过ACK端通知发
    送端;
  • 窗口大小字段越大, 说明网络的吞吐量越高;
  • 接收端一旦发现自己的缓冲区快满了, 就会将窗口大小设置成一个更小的值通知给发送端;
  • 发送端接受到这个窗口之后, 就会减慢自己的发送速度;
  • 如果接收端缓冲区满了, 就会将窗口置为0; 这时发送方不再发送数据, 但是需要定期发送一个
    窗口探测数据段, 使接收端把窗口大小告诉发送端
拥塞控制

网络更新当前时间的网络来动态调整收发的频率就叫拥塞控制。
TCP引入 慢启动 机制, 先发少量的数据, 探探路, 摸清当前的网络拥堵状态, 再决定按照多大的速度传输数据;
在这里插入图片描述

  • 此处引入一个概念程为拥塞窗口;

  • 发送开始的时候, 定义拥塞窗口大小为1;

  • 每次收到一个ACK应答, 拥塞窗口加1;

  • 每次发送数据包的时候, 将拥塞窗口和接收端主机反馈的窗口大小做比较, 取较小的值作为实际发送的窗口;
    在这里插入图片描述

  • 为了不增长的那么快, 因此不能使拥塞窗口单纯的加倍

  • 此处引入一个叫做慢启动的阈值

  • 当拥塞窗口超过这个阈值的时候, 不再按照指数方式增长, 而是按照线性方式增长

  • 当TCP开始启动的时候, 慢启动阈值等于窗口最大值;

  • 在每次超时重发的时候,慢启动阈值会变成原来的一半, 同时拥塞窗口置回1;

  • 少量的丢包, 我们仅仅是触发超时重传; 大量的丢包, 我们就认为网络拥塞;

  • 当TCP通信开始后, 网络吞吐量会逐渐上升; 随着网络发生拥堵, 吞吐量会立刻下降;

  • 拥塞控制, 归根结底是TCP协议想尽可能快的把数据传输给对方, 但是又要避免给网络造成太大压力的折中方案.

延迟应答
  • 假设接收端缓冲区为1M. 一次收到了500K的数据; 如果立刻应答, 返回的窗口就是500K;
  • 但实际上可能处理端处理的速度很快, 10ms之内就把500K数据从缓冲区消费掉了;
  • 在这种情况下, 接收端处理还远没有达到自己的极限, 即使窗口再放大一些, 也能处理过来;
  • 如果接收端稍微等一会再应答, 比如等待200ms再应答, 那么这个时候返回的窗口大小就是
    1M;
策略
每隔一段时间(固定时间)延迟应答一次;
每隔N次(>=2)延迟应答一次;

一定程度加速发送消息的速度。
延迟应答(200MS)的时间一定小于超时重传的时间(500MS)。
窗口越大, 网络吞吐量就越大, 传输效率就越高. 我们的目标是在保证网络不拥塞的情况下尽量提高传输效率;

捎带应答

针对对于延时应答的性能优化。
在这里插入图片描述

TCP沾包问题

TCP 异常情况

  • 可挽救:电脑重启或者进程结束的时候,它会发送 FIN 请求,和正常关闭TCP是没有什么区别的;
  • 不可挽救:电脑掉电/网线中断:TCP 报活定时器,会定时检测对方是否在线,如果检测的结果是没有任何响应,说明已经掉线,直接释放连接。

小结

  • 稳定性:确认应答;超时重传;连接管理;流量控制;拥塞控制。
  • 保证性能:滑动窗口;延时应答;捎带应答。
  • 基于TCP应用层协议:HTTP;SSH;Telent;FTP:SMTP。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/XSAAA/article/details/115921728

智能推荐

异常:javassist.CannotCompileException: [source error] getEveryUserNum_orika cannotcompileexception-程序员宅基地

文章浏览阅读1.3k次。添加接口后dubbo启动失败,抛出的异常。各种调试、测试,没有发现代码的问题。于是百度了一下,说可能是由于提供的接口以getXXX 开头,而且接口没有返回值,从而出现此种异常。因此尝试修改方法名称,再次启动,成功!果然因为如此!但是这是为什么呐?原因在于dubbo暴露服务,将getxxx开头的方法,当做获取属性方法来进行编译,然后方法没有返回值,所以抛出异常。贴上dubbo的动..._orika cannotcompileexception

js时间格式化函数formatDate(RegExp)-程序员宅基地

文章浏览阅读483次。((‘00’ + o[k]).substr((’’ + o[k]).length))) 这个地方真的巧妙。欢迎关注微信公众号(大明前端)export function formatDate(date, fmt) { if (typeof date == 'string') { return date; } if (!fmt) fmt = "yyyy-MM-dd hh:mm:ss"; if (!date || date == null) return null; let o

[原]通过 dumpsys SurfaceFlinger 分析Android 系统图层_surfaceflinger log-程序员宅基地

文章浏览阅读1.6w次,点赞3次,收藏16次。一、通过 dumpsysSurfaceFlinger 分析Android 系统图层:从下面的dumpsys log看出当前系统有三个图层(红色部分是每个图层的坐标和大小),从最底层到上层分别是ImageWallpaper(壁纸), SurfaceView(视频小窗口), launcher(桌面)。其中视频小窗口用Overlay的方式独立输出到视频层,这样的话只有壁纸层和桌面层通过GPU混合_surfaceflinger log

一文搞懂 Java 线程中断_java 线程退出会打印什么-程序员宅基地

文章浏览阅读3.3k次,点赞6次,收藏12次。在之前的一文《如何"优雅"地终止一个线程》中详细说明了 stop 终止线程的坏处及如何优雅地终止线程,那么还有别的可以终止线程的方法吗?答案是肯定的,它就是我们今天要分享的——线程中断。下面的这断代码大家应该再熟悉不过了,线程休眠需要捕获或者抛出线程中断异常,也就是你在睡觉的时候突然有个人冲进来把你吵醒了。try { Thread.sleep(3000);} catch (Interrup..._java 线程退出会打印什么

RedHat/CentOS-7搭建FTP服务器_如何用centos7访问ftp服务器-程序员宅基地

文章浏览阅读4.6k次,点赞2次,收藏17次。前言:本文以搭建vsftp为例进行。1、安装vsftpd和lftp:yum -y install vsftpd lftp2、创建用户://创建用户useradd -d /ftpfile -s /sbin/nologin test//-d-->更改用户的家目录为/ftpfile//-s /sbin/nologin --> 不让用户登录linux系统,只能以..._如何用centos7访问ftp服务器

uniapp分包加载运行到微信小程序文件查找失败_在uniapp进行分包微信小程序检测不到路径-程序员宅基地

文章浏览阅读2.6k次。uniapp分包加载运行到微信小程序文件查找失败我按照uniapp框架将写好的代码进行子级分包加载,运行时报错,查找原因是APP和小程序不一样,小程序最好放在root根目录下,没办法,只好换成官方给的方法错误运行跟换目录后运行..._在uniapp进行分包微信小程序检测不到路径

随便推点

'netstat -....' 不是内部或外部命令,也不是可运行的程序 或批处理文件。_netstat-ano' 不是内部或外部命令,也不是可运行的程序 或批处理文件。-程序员宅基地

文章浏览阅读5.2k次,点赞3次,收藏5次。这个时候发现有好多的互联网大侠在网上给出答案,不知道为啥,我一个也用不到小白答案:也许这一次你就成功了!执行:系统高级环境变量设置一>用户变量一>找到path一>在里面新建加入C:\WINDOWS\system32一>完成任务没有必要把系统中的path也改了..._netstat-ano' 不是内部或外部命令,也不是可运行的程序 或批处理文件。

【Linux线程同步专题】五、进程间同步_linux c++进程间同步与互斥-程序员宅基地

文章浏览阅读686次,点赞8次,收藏10次。《Linux从小白到大神》 | 系统学习Linux开发、VIM/GCC/GDB/Make工具、Linux文件IO、进程管理、进程通信、多线程等,请关注专栏免费学习。_linux c++进程间同步与互斥

因果推断笔记——数据科学领域因果推断案例集锦(九)-程序员宅基地

文章浏览阅读1.5w次,点赞37次,收藏214次。2 腾讯看点:视频笔记​2.1 观测数据 、 实验数据的理论介绍​![image.png](https://img-blog.csdnimg.cn/img_convert/c66bdbcdd86d5031040f51924397952d.png#clientId=u8e2473a0-856a-4&from=paste&height=746&id=ud2728b80&margin=[object Object]&name=image.png&origin_因果推断笔记

【Mysql系列】Data too long_mysql data to long-程序员宅基地

文章浏览阅读3.3k次。MySQL 报 Data too long for column ‘…’今天设计了一张表 其中一个字段我设置的类型是 text 类型的 ,按照正常的情况下 text 是不限制长度的,因此插入了一段很长的 txt 内容 ,结果出现了 悲剧性的事情,提示了 数据太长 Data too long for column ‘…’ at row 1 这就很尴尬了,百度了半天,有去改配置的,有去改编码的,最后没有一个有效的。那么好吧,还是先去看看数据结构吧text 嗯 ,没错,双击一下,我上翻翻下翻翻,突然发现,_mysql data to long

伪随机生成器具体实现——杂乱的方法_杂凑函数生成伪随机数发生器-程序员宅基地

文章浏览阅读1k次。一 点睛具体的伪随机生成器有下面几种杂乱的方法 线性同余法 单向散列函数 密码法 ANSI X9.17二 杂乱的方法——这种方法不可取可能有人会说,既然是要生成杂乱无章的数列,那么用杂乱无章的算法不就可以了吗?比如说,可以使用连程序员都无法理解的混乱又复杂的方法。然而,这种做法是错误的。如果只是把算法搞得复杂,那么算法是无法用于密码技术的。其中一个原因就是周期太短。使用复..._杂凑函数生成伪随机数发生器

Java集合中HashMap日常问题及解决办法_hashmap本地没问题,服务器上不生效-程序员宅基地

文章浏览阅读365次。前言  今天在学习Java中Session的时候,利用了Session可持久化保存服务器端的特性尝试做了一下用HashMap嵌套的购物车(没有将购物车的商品信息保存在数据库中),之所以做的这么麻烦是为了巩固之前学习的Map知识和锻炼逻辑能力,正好也在其中遇到了一个关于HashMap 的问题,在此做个小小的记录,方便日后查看。问题  服务器端保存购物车商品信息用的是HashMap嵌套,内层H..._hashmap本地没问题,服务器上不生效

推荐文章

热门文章

相关标签