限于博主水平有限不敢说指南,但应该能够避免刚学TCP的同学出现找不着北的情况。

TCP与UDP的区别

区别:

  • UDP是无连接的,而TCP是面向连接的,传数据前要先建立连接。
  • UDP可以一对多,多对多通讯,而TCP只能一对一。
  • UDP使用最大努力交付,即不保证可靠交付。而TCP是可靠交付数据,并且有拥塞控制和流量控制机制。
  • UDP是面向报文的,适合一次性传输少量数据。而TCP是面向字节流的

总的来说UDP不太靠谱,自管把数据发出去,丢了也不管。就好像两个人说话,其实一个人只管自己说自己的。

相比之下,TCP就靠谱多了,它通过序列号和确认应答机制保证连接的可靠性,任何一方向对方发送消息(SYN),都要收到回应(ACK)。相当于两个人正常聊天,接下来的谈话内容会根据对方的反应做出调整,比如对方开小差没有听到你刚才讲什么,就重复一遍刚刚说的话。

上图写的只是相对序列号(相对于初始序列号,序列号如果一直是一个固定值,会增加被攻击的风险),初始序列号(ISN)的确定是在连接建立也就是三次握手阶段。

三次握手

同步序列号

握手的首要目的是告知对方自己的初始序列号,只有同步了序列号才能实现可靠传输,比如拥塞控制,消息重发等等。

虽然两次握手就能同步双方的序列号,但无法保证客户端是否接收到了服务端发过去的初始序列号,所以我们需要进行第三次握手来确认。

双方都需要确认一次自己发过去的序列号对方有没有收到,三次握手之后双方就都能明确自己和对方的收发能力是正常的。

实际上任意次的握手都不可靠,三次是双方互相明确对方收发能力的最低值。这 一点可以看看两军问题

第一次握手:客户端在给服务端数据通信之前,会发送连接请求并等待确认应答,此时TCP首部SYN为1,seq为随机生成的序列号(X)。

第二次握手:服务器接受到连接请求之后,会进行答复这时SYN仍为1,确认应答号ack为X+1,表示你发过来的请求我接收到了。同时服务器也会生成一个随机序列号y写入seq,等待客户端的确认应答。

第三次握手:前两次都是通过TCP首部发送SYN包作为建立连接的请求,并未携带数据。三次握手的最后一次握手可以在报文段负载中携带数据,并且因为连接已经建立,所以在之后的报文中SYN都为0(包括最后一次握手),双方正式开始通信。

前两次握手都不能携带数据,并且需要消耗掉一个序列号,也就是seq要加一。

第三次握手可以携带数据,如果不携带数据则不消耗序列号。也就是说三次握手结束后,客户端发送的第一个报文中的seq仍然为x+1

实际上,本来是四次握手的

Alice ---> Bob SYNchronize with my Initial Sequence Number of X

Alice <--- Bob I received your syn, I ACKnowledge that I am ready for [X+1]

Alice <--- Bob SYNchronize with my Initial Sequence Number of Y

Alice ---> Bob I received your syn, I ACKnowledge that I am ready for [Y+1]

因为二三步的接收对象相同,所以可以合为一步

认识TCP首部

突然出现SYN,seq这些字母你可能感觉晕乎乎的。特别是ACK和ack,更是让人傻傻分不清楚。现在就来认识一下他们吧。

图中的序列号就是seq(发送数据的顺序编号),它的值是本报文段所发送数据的第一个字节的序号。比如这次发送的数据包是由文件的第1-100个字节,那么seq的值为1.

小写ack对应确认应答号,表示期望收到对方下一个报文段数据的第一个字节的序号。比如已经收到1-100个字节数据后,那么确认应答号就应为101,这样发送端下次就会发送101字节及其之后的数据过来。

需要注意的是只有控制位ACK为1时,确认应答号ack才有效。

防止历史连接扰乱通讯

如果你有过打游戏突然掉线或者异常卡顿的经历,我相信你对网络通讯并不像“如意如意,随我心意”那么顺利有着深刻的认识

假设我们对服务器发送了连接请求,但因为物理链路选择的问题,迟迟没有到达。超过了等待时间之后,重发了一次请求,这一次很快就顺利建立起连接了。但没过多久之前那个请求报文风尘仆仆的来到服务器这,也建立起了连接。

不过还好初始序列号生成的算法比较巧妙:

ISN=M+F(本地IP,本地端口,目的IP,目的端口)

M是过四毫秒就加一的计时器,F是根据上面四个参数进行映射的哈希函数

这样就能保证客户端能过凭借序列号判断这是否是一个过期连接(通过跟记住的最后接收到的seq进行比对)。

如果是,则发送RST报文给服务端,终止这个过期连接。不会让服务端还傻傻的等着客户端发数据,避免了资源的浪费。

从这里也可以看出,序列号seq是多么重要。因为TCP没有时间戳,所以通过同步双方的序列号来“校准双方的时间”就显得尤为重要。

TCP的可靠连接是通过序列号和确认应答来实现的

SYN洪水攻击

SYN洪水攻击(SYN flood attack)利用了TCP协议 3次握手的原理,攻击者发送大量建立连接的网络包,但却不实际建立连接(不进行第三次握手),导致服务器的连接资源耗尽。

这种攻击因为SYN cookie技术的产生,在现代网络已经不奏效了。

SYN cookie的具体做法是:

服务器只在握手完成之后分配资源,在这之前,它会根据特殊的算法生成一个cookie(seq序列号)发给对方。服务器本身并不记忆该cookie。

因为该cookie的生成与对方的IP和端口号有关,所以服务器可以凭此重新算出cookie,并与发过来的报文段中的ack进行比对。

如果对方是合法的连接,服务器就生成一个具有套接字的全开连接。如果不合法,那咱也不亏,服务器没有为它分配过任何资源。

一般SYN cookie只在半连接队列爆满的情况下才会启用。除此之外,常见的防范方式还有SYN Proxy防火墙,Syn Cache技术等。

多亏了序列号和确认应答

滑动窗口

如果传输比较大的数据,一般会将其分为小包,进行分段传输。如果每发送一个数据包都要等待对方确认之后再发下一个,这段时间内什么都不做,看起来太浪费了。

TCP采用滑动窗口来避免资源的浪费:在等待ACK号的这段时间,继续发送后面的数据包。如果收到了ACK号,那么就将该ACK之前的数据包从缓存中清除。

不过这样做有些问题,因为对方可能无法在短时间内处理大量的数据包,导致后来的都被丢弃(缓冲区溢出)。所以在连接的时候,双方应该要明确发送和接收能力。

在TCP首部的可选字段中,双方会协商好能够接收的最大数据量(一般称为窗口大小),它的值一般与接收方缓冲区大小相等。

连接的两端都有各自的接收缓存和发送缓存,无论哪方都能同时收发信息,因此TCP提供的是全双工服务。

拥塞控制

拥塞控制的目的是防止过多数据传输,使得传输链路过载,甚至造成瘫痪。在网络畅通的时候,我们就多发点,猛踩油门;网络差的时候,就别一个劲的发送大量报文添堵了。

TCP采取慢启动、拥塞避免、快速重传、快速恢复来进行拥塞控制。

  • 慢启动:

    刚建立起的连接,拥塞窗口大小从默认初始值开始,大胆进行试探性指数增长。
  • 拥塞避免:

    当达到慢启动阈值(ssthresh)时,再进行指数增长显得有点鲁莽了。这时候我们改变策略,采取加法的形式谨慎增加cwnd
  • 快速重传:

    当发现收到四个相同的ACK时(检测到三个冗余ACK),进行快速重传。即立马发送这个丢失的报文段,无需等待超时重传定时器。
  • 快速恢复:

    发生快速重传之后就会进入快速恢复阶段,此时ssthresh=cwnd/2,cwnd=cwnd/2,之后迁移到慢启动阶段。

四次挥手

断开连接的步骤居然要比建立连接还多,这是怎么回事?难道不能像握手那样:

  • 客户端告诉服务器我要断开连接了
  • 服务端回复好的,并且告诉客户端我也准备断开了
  • 客户端收到服务端的确认之后,再给服务端发送一个确认消息

这样三步不就解决了吗?

断开连接与建立连接还是有些不同的,因为建立连接之前,双方是没有任何通讯的。但在结束连接的时候,双方可能还存在着没有传输完成的数据包。

所谓上山容易下山难,多加一次挥手是为了防止出现误操作。

如果是三次挥手,这边客户端要求服务器重发的请求刚出去,就收到对面说断开连接的消息,实在是让人错手不及

所以我们得分四步进行。

并且连接关闭之后,并不会马上删除相关数据。这是为了防止乌龙事件的产生。

如果因为网络原因,最后一步ACK丢了。服务器迟迟未收到客户端对其断开连接的确认,重发了FIN。

但好巧不巧,客户端的新连接就建立在这个之前断开的端口号上。得,执行断开操作,全乱套了。

TCP学习指北的更多相关文章

  1. Git学习指北

    learnGitBranching:一个可视化学习 git 的网站 learngitbranching.js.org,虽然项目有些悠久,如果学习 git 的话可以来玩下

  2. 后端API入门到放弃指北

    后端API入门学习指北 了解一下一下概念. RESTful API标准] 所有的API都遵循[RESTful API标准]. 建议大家都简单了解一下HTTP协议和RESTful API相关资料. 阮一 ...

  3. Python 简单入门指北(二)

    Python 简单入门指北(二) 2 函数 2.1 函数是一等公民 一等公民指的是 Python 的函数能够动态创建,能赋值给别的变量,能作为参传给函数,也能作为函数的返回值.总而言之,函数和普通变量 ...

  4. Python 简单入门指北(一)

    Python 简单入门指北(一) Python 是一门非常容易上手的语言,通过查阅资料和教程,也许一晚上就能写出一个简单的爬虫.但 Python 也是一门很难精通的语言,因为简洁的语法背后隐藏了许多黑 ...

  5. 可能比文档还详细--VueRouter完全指北

    可能比文档还详细--VueRouter完全指北 前言 关于标题,应该算不上是标题党,因为内容真的很多很长很全面.主要是在官网的基础上又详细总结,举例了很多东西.确保所有新人都能理解!所以实际上很多东西 ...

  6. [转] iOS开发者的Weex伪最佳实践指北

    [From] http://www.cocoachina.com/ios/20170601/19404.html 引子 这篇文章是笔者近期关于Weex在iOS端的一些研究和实践心得,和大家一起分享分享 ...

  7. JavaScript 词法作用域不完全指北

    在 JavaScript 作用域不完全指北 中,我们介绍了作用域的概念以及 JavaScript 引擎.编译器和作用域的关系.作用域有两种主要的工作模型:词法作用域和动态作用域.其中最为普遍的也是大多 ...

  8. [Android Studio] 2019年Android Studio配置指北

    Android Studio是我学习Android开发路上的第一块绊脚石,新建一个项目,一行代码没动,直接编译不起来,我太难了,所以本文叫指北 本文讲解在9102年如何在国内网络不通畅的情况下流畅的使 ...

  9. Markdown 标记语言指北 - 源码

    这是上一篇博客的源代码. 这是班刊约稿的一篇文章. 全文约6000字, 预计需要 60 分钟读完. # Markdown 标记语言指北 #### TOC 1. [什么是 Markdown?](#%E4 ...

随机推荐

  1. 2. import 与 from...import 导入模块

    1. 导入整个模块 格式: import somemodule2. 从某个模块中导入某个函数 格式: from somemodule import somefunction3. 从某个模块中导入多个函 ...

  2. (1)为什么要使用webpack?

    1.在网页中有哪些常见的静态资源? Js: .js .jsx .coffee .ts Css: .css .less .sass .scss Images: .jpg .png .gif .bmp . ...

  3. Websphere修改web.xml不生效的解决办法(转)

    在websphere下部署了一个java工程后,如果修改了web.xml文件,重新启动这个java工程发现websphere并没有自动加载web.xml文件,即修改后的web.xml并不起作用,除非重 ...

  4. Ethical Hacking - NETWORK PENETRATION TESTING(15)

    ARP Poisoning - arpspoof Arpspoof is a tool part of a suit called dsniff, which contains a number of ...

  5. 面试官:连Spring三级缓存都答不好,自己走还是我送你?

    面试官:简历上写了精通Spring,那你回答一下Spring为什么用“三级缓存”去解决循环依赖? 我:.......应该有三个缓存的map结构 面试官:具体回答一下 我:平时没认真深入过 面试官:公司 ...

  6. JQuery如何在验证表单失败的情况下阻止表单提交

    自定义验证时,使用了return false和event.preventDefault(),但是验证失败之后表单还是提交了 这个问题我也碰到了,尝试了多次也没有用,在调试的时候也发现确实return了 ...

  7. JAVA I/O基本操作

    JAVA I/O基本操作 JAVA文件操作 JAVA字节流 JAVA字符流 JAVA缓存流 JAVA对象流 JAVA数据流 本文主要借鉴以下博客和网站: how2j.cn 深入理解java中的I/O ...

  8. 聊一聊Flutter的setState()

    Flutter 里面包含两种widget 一种可变的,一种不可变的: 在可变的widget中可以使用 setstate(){} 函数. 官方也给出了例子: _onClick(){ setState() ...

  9. 一文了解JDK12 13 14 GC调优秘籍-附PDF下载

    目录 简介 那些好用的VM参数 G1的变化 配置FlightRecorder RAM参数 JDK13中的ZGC RTM支持 总结 简介 想了解JDK12,13,14中的GC调优秘籍吗?想知道这三个版本 ...

  10. matplotlib绘制子图

    fig,subs = plt.subplots(2,2) subs[0][0].plot(data_math_C1) subs[0][0].set_title('C_1 曲线') subs[0][1] ...