libjingle源码解析(3)-【PseudoTcp】建立UDP之上的TCP(1):连接和关闭

本文涉及的产品
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
简介:

PseudoTcp - 建立UDP之上的TCP1):连接和关闭

mail:lihe21327 [at] gmail [dot] com

最近阅读了LibjinglePseudoTcp.LibJingle很是下功夫做P2P了,在UDP之上做了可靠的传输协议PseudoTcp.

了解PseudoTcp之前,我们需要了解一些TCP的特性。


根据《TCP/IP详解》卷1,可以总结如下:

1.TCP是面相连接的,他需要3次握手和4次终止过程。

2.TCP支持Nangle算法和经受时延的确认来控制报文段数目。

3.TCP含有滑动窗口来控制接收方的流量。

4.TCP支持超时与重传。

5.TCP支持拥塞避免算法。

6.TCP具有坚持定时器和保活定时器

7.TCP要支持路径MTU发现、长肥管道、时间戳选项。

那我们一起剖析一下PseudoTcp实现了上面哪些功能。

PseudoTcp(以后简称PTCP吧)的格式:

通过结构Segment 定义此报文头部:

struct Segment {

    uint32 convseqack;

    uint8 flags;

    uint16 wnd;

    const char * data;

    uint32 len;

    uint32 tsvaltsecr;

  };

各个字段的含义如下:

  A)Conversation Number : 流水号,是用来标识此次连接。即TCP里所谓的本地IP:本地端口-远程IP:远程端口,4组合为一个流水号。因为PTCPUDP之上的(当然也可以是其他协议之上),如果socket没有绑定到本地端口,可能获取的不是需要的数据。如果获取的Conv Number不一样,接收方会发送RST(不过PTCP里已经注释了此段代码)。此外,PTCP并不关心他的传输层是有一个连接还是多个连接,她只关心CONV Number是否一致。

  B)Seq Number:32位序号,即此数据表示的序列,不一定从0开始

  C)Ack Number:32确认序列号。确认已经获取到的数据序列加1,即下一个需要接受的序列号。

  D)Control:现未使用

  E)URG:紧急指针,1bit

  F)ACK:确认序列号有效,1bit

  G)PSH:接收方尽可能将这个报文送给应用层,1bit

  H)RST:重置连接

  I)FIN:表示发送完所有数据,断开连接。

  J)Window:窗口大小

  K)TimeStamp Sending:本端发送包时间(采用以本端的时间计算方式)

  L)TimeStamp Receiving:对方最近接收包时间(采用以对方的时间计算方式)

  M)Data:数据

  注:上面的E-I的含义,在实现上完全不同。下面会提到。


PTCP的状态:

  TCP_LISTEN:监听

  TCP_SYN_SENTSYN包已经发送

  TCP_SYN_RECEIVED:已经接收SYN

  TCP_ESTABLISHED:已经建立连接

  TCP_CLOSED:已经关闭连接


PTCP的状态转移相对TCP来说简单多了,TCP如下:

 

3路握手:

TCP建议连接时需要来回总共有3TCP包来做握手,即

  A)SYN[A]:

  B)ACK[B],SYN[A+1]

  C)ACK[B+1]


PTCP握手过程如下:

  当开始时两端都处于TCP_LISTEN状态。

  当C端发送SYN包到S端时,C端处于TCP_SYN_SENT状态

  当S端处于TCP_LISTEN时收到SYN包,S端转为TCP_SYN_RECEIVED

  当S端处于TCP_SYN_RECEIVED时,发送ACK时状态不变

  当C端处于TCP_SYN_SENT时,收到ACK,则转为TCP_ESTABLISHED

  当S端处于TCP_SYN_RECEIVED,收到非控制包时转为TCP_ESTABLISHED

  这里解释一下控制包:上面PTCP协议头结构里的第13个字节处(即URGACK等在的字节)其实只取3个值之一:

    0:数据包

    0x02CTL包,当握手时使用。

    0x04RST包。现在发此段包的代码被注释掉。

所以控制包,指的是握手时才会发送,握手完之后都属于数据包。

可见PTCP的握手过程和TCP的握手过程有微小的差异。当C端转为TCP_ESTABLISHED后,等到有数据才会发送给S端(而不是立即),S端直到只有等到有数据的包时,才把状态改为TCP_ESTABLISHED。而TCP是,如果没有数据会立即发送,S端只要收到ACK就改为ESTABLISHED状态。


连接建立时超时:

C端发送完SYN包之后,一直没有响应时,没过3SC端会发送一个SYN请求。直到发送30次之后,还没有收到回包,则停止发送并关闭连接。即等待时间为3*30=90S,而大多数TCP实现的超时时间为75S


最大报文段长度(MSS)

TCP默认MSS536,即取MTU576 X.25 Networks),包括20个字节的IP头和20个字节的TCP头。

对于PTCP,默认MTU取为65536,即UDP容纳的最大长度,那么MSS取值为65536-116

116的计算来自:

  PACKET_OVERHEAD = HEADER_SIZE + UDP_HEADER_SIZE + IP_HEADER_SIZE + JINGLE_HEADER_SIZE

  JINGLE_HEADER_SIZE用于Relay包,具体需要了解STUN协议和TURN协议。

MTU的发现完全由调用方来决定,PTCP只提供了接口来更新MTU

Libjingle里,对于win32,枚举下面数组PACKET_MAXIMUMS,然后通过WinPing来发现此次PTCP连接的MTU。如果没有获取到MTU,默认取值为1280(此时MSS1280-116=1164)。

为什么MTU默认取值为1280呢,有什么数据依据呢?

// Standard MTUs

  const uint16 PACKET_MAXIMUMS[] = {

    65535,    // Theoretical maximum, Hyperchannel

    32000,    // Nothing

    17914,    // 16Mb IBM Token Ring

    8166,   // IEEE 802.4

    //4464,   // IEEE 802.5 (4Mb max)

    4352,   // FDDI

    //2048,   // Wideband Network

    2002,   // IEEE 802.5 (4Mb recommended)

    //1536,   // Expermental Ethernet Networks

    //1500,   // Ethernet, Point-to-Point (default)

    1492,   // IEEE 802.3

    1006,   // SLIP, ARPANET

    //576,    // X.25 Networks

    //544,    // DEC IP Portal

    //512,    // NETBIOS

    508,    // IEEE 802/Source-Rt Bridge, ARCNET

    296,    // Point-to-Point (low delay)

    //68,     // Official minimum

    0,      // End of list marker

  };

PTCP的关闭。

TCP的关闭时由4步骤完成。


  1. FIN[A]

  2. ACK[A+1]

  3. FIN[B]

  4. ACK[B+1]

然而,有时候可以做到3步,即上面的2,3步可以合成在一个TCP包里发送。对于上面只完成前两步的状态成为半关闭状态,此时发送FIN[A]的端表示自己不再有多余的数据要发送,但还能接收数据。

当调用PTCPClose方法时,此端丢弃对方发过来的数据,只做应答,即只发送对方发来数据的ACK。并且等到此方数据都发送完,需关闭整个连接。以此看来,PTCP没有半关闭状态,并且PTCP也只是用来支持P2P用的,不需要半关闭状态。

2MSL等待状态

MSL是指一个数据包在网络上存在的最长时间。而2MSL是指当主动关闭方发送被动关闭方发送的FIN对应的ACK时,如果这个ACK被丢失了,则被动关闭方超时重发最后的FIN,此时主动关闭方再次发ACK,当主动关闭方发送第一个FIN对应的ACK到,拿到最后的FIN之间的时间段最长为2MSL。那为什么主动关闭方处于2MSL等待状态呢?是因为,如果主动关闭方发送了第一个FIN对应的ACK之后,放弃了此连接,那么下一个新建的连接有可能复用此连接(即同一个插口对),此时新建的连接有可能因为上一个丢失的ACK,而收到重发的FIN,导致连接被关闭。

然而PTCP不存在半关闭的概念,故2MSL等待状态也随之没有。此外,PTCP是用来做P2P的,两者之间的连接时双方协商定义的,并且PTCP在头部给予了Conversation number的概念,以便协商中防止产生同一个连接的产生。

复位报文段

TCP存在如下情况时会产生复位报文段。

  A.当服务器没有开启指定的连接端口时,对于UDP来说产生端口不可达,而TCP产生RST报文

  B.当一端产生异常终止时,会发送RST报文。即当设置SO_LINGER套接口选项时,close套接口会产生RST报文。

  C.检测到半打开连接,当接收方异常终止重启后接收对方在旧的连接上传过来的数据时,会发送RST报文。

对于PTCP来说,现在没有一个地方会发送RST报文(之前有过的被注释了,当收到不是当前的CONV时会发送RST),但如果一旦收到了RST报文,则立即关闭此连接。

同时打开

TCP的同时打开情景是如下:当C用端口7777连接S的端口8888,同时S用端口8888连接C的端口7777,此时包的顺序如下:

  1) SYN[A]

  2) SYN[B]

  3) ACK[A+1]

  4) ACK[B+1]

显然上面的握手从3次变为4次。

PTCP的同时打开,也类似如上,由4个包来完成握手。

  1) C端发送SYN时,状态变为TCP_SYN_SENT

  2) 同时S端发送SYNSC的状态此时都为TCP_SYN_SENT

  3) C,S同时向对方(可以不是同时)发送ACK,此时CS状态都变为TCP_ESTABLISHED

同时关闭

TCP是支持CS同时关闭的。

  1)C,S同时发送FIN,状态变为FIN_WAIT_1

  2)C,S同时收到FIN,并发送ACK,状态变为CLOSING

  3)C,S同时收到ACK,两个状态都变为TIME_WAIT

对于PTCP,没有像TCP,不存在FIN包,显然对关闭状态的维护不是很完美。也同样,看不到同时关闭的情形,这些交给底层传输层(UDP)等之类来完成,由调用方来维护状态。

为什么PTCP没有提供FIN报文以及对应的状态呢?

TCP选项

TCP保留40个字节传输其他选项,主要有窗口扩大因子,时间戳选项,MSS长度等。

PTCP也通过一种方式来增加其他选项,如MSS和窗口扩大因子。当传输的是控制包且有数据内容时,如果第一个字节为CTL_CONNECT,则会调用方法parseOptions来解析是否含有MSS,窗口扩大因子等等选项。这些选项的实现细节后续会提及(时间戳选项直接在报文头里有,固这个选项很重要,后续会提到此选项的作用)。

相关实践学习
通过Ingress进行灰度发布
本场景您将运行一个简单的应用,部署一个新的应用用于新的发布,并通过Ingress能力实现灰度发布。
容器应用与集群管理
欢迎来到《容器应用与集群管理》课程,本课程是“云原生容器Clouder认证“系列中的第二阶段。课程将向您介绍与容器集群相关的概念和技术,这些概念和技术可以帮助您了解阿里云容器服务ACK/ACK Serverless的使用。同时,本课程也会向您介绍可以采取的工具、方法和可操作步骤,以帮助您了解如何基于容器服务ACK Serverless构建和管理企业级应用。 学习完本课程后,您将能够: 掌握容器集群、容器编排的基本概念 掌握Kubernetes的基础概念及核心思想 掌握阿里云容器服务ACK/ACK Serverless概念及使用方法 基于容器服务ACK Serverless搭建和管理企业级网站应用
目录
相关文章
|
16天前
|
存储 设计模式 算法
【23种设计模式·全精解析 | 行为型模式篇】11种行为型模式的结构概述、案例实现、优缺点、扩展对比、使用场景、源码解析
行为型模式用于描述程序在运行时复杂的流程控制,即描述多个类或对象之间怎样相互协作共同完成单个对象都无法单独完成的任务,它涉及算法与对象间职责的分配。行为型模式分为类行为模式和对象行为模式,前者采用继承机制来在类间分派行为,后者采用组合或聚合在对象间分配行为。由于组合关系或聚合关系比继承关系耦合度低,满足“合成复用原则”,所以对象行为模式比类行为模式具有更大的灵活性。 行为型模式分为: • 模板方法模式 • 策略模式 • 命令模式 • 职责链模式 • 状态模式 • 观察者模式 • 中介者模式 • 迭代器模式 • 访问者模式 • 备忘录模式 • 解释器模式
【23种设计模式·全精解析 | 行为型模式篇】11种行为型模式的结构概述、案例实现、优缺点、扩展对比、使用场景、源码解析
|
16天前
|
设计模式 存储 安全
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
结构型模式描述如何将类或对象按某种布局组成更大的结构。它分为类结构型模式和对象结构型模式,前者采用继承机制来组织接口和类,后者釆用组合或聚合来组合对象。由于组合关系或聚合关系比继承关系耦合度低,满足“合成复用原则”,所以对象结构型模式比类结构型模式具有更大的灵活性。 结构型模式分为以下 7 种: • 代理模式 • 适配器模式 • 装饰者模式 • 桥接模式 • 外观模式 • 组合模式 • 享元模式
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
|
16天前
|
设计模式 存储 安全
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
创建型模式的主要关注点是“怎样创建对象?”,它的主要特点是"将对象的创建与使用分离”。这样可以降低系统的耦合度,使用者不需要关注对象的创建细节。创建型模式分为5种:单例模式、工厂方法模式抽象工厂式、原型模式、建造者模式。
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
|
18天前
|
网络协议
TCP报文格式全解析:网络小白变高手的必读指南
本文深入解析TCP报文格式,涵盖源端口、目的端口、序号、确认序号、首部长度、标志字段、窗口大小、检验和、紧急指针及选项字段。每个字段的作用和意义详尽说明,帮助理解TCP协议如何确保可靠的数据传输,是互联网通信的基石。通过学习这些内容,读者可以更好地掌握TCP的工作原理及其在网络中的应用。
|
18天前
|
监控 网络协议 网络性能优化
不再困惑!一文搞懂TCP与UDP的所有区别
本文介绍网络基础中TCP与UDP的区别及其应用场景。TCP是面向连接、可靠传输的协议,适用于HTTP、FTP等需要保证数据完整性的场景;UDP是无连接、不可靠但速度快的协议,适合DNS、RIP等对实时性要求高的应用。文章通过对比两者在连接方式、可靠性、速度、流量控制和数据包大小等方面的差异,帮助读者理解其各自特点与适用场景。
|
27天前
|
存储 网络协议 安全
用于 syslog 收集的协议:TCP、UDP、RELP
系统日志是从Linux/Unix设备及网络设备生成的日志,可通过syslog服务器集中管理。日志传输支持UDP、TCP和RELP协议。UDP无连接且不可靠,不推荐使用;TCP可靠,常用于rsyslog和syslog-ng;RELP提供可靠传输和反向确认。集中管理日志有助于故障排除和安全审计,EventLog Analyzer等工具可自动收集、解析和分析日志。
111 2
|
2月前
|
缓存 监控 Java
Java线程池提交任务流程底层源码与源码解析
【11月更文挑战第30天】嘿,各位技术爱好者们,今天咱们来聊聊Java线程池提交任务的底层源码与源码解析。作为一个资深的Java开发者,我相信你一定对线程池并不陌生。线程池作为并发编程中的一大利器,其重要性不言而喻。今天,我将以对话的方式,带你一步步深入线程池的奥秘,从概述到功能点,再到背景和业务点,最后到底层原理和示例,让你对线程池有一个全新的认识。
60 12
|
1月前
|
PyTorch Shell API
Ascend Extension for PyTorch的源码解析
本文介绍了Ascend对PyTorch代码的适配过程,包括源码下载、编译步骤及常见问题,详细解析了torch-npu编译后的文件结构和三种实现昇腾NPU算子调用的方式:通过torch的register方式、定义算子方式和API重定向映射方式。这对于开发者理解和使用Ascend平台上的PyTorch具有重要指导意义。
|
17天前
|
安全 搜索推荐 数据挖掘
陪玩系统源码开发流程解析,成品陪玩系统源码的优点
我们自主开发的多客陪玩系统源码,整合了市面上主流陪玩APP功能,支持二次开发。该系统适用于线上游戏陪玩、语音视频聊天、心理咨询等场景,提供用户注册管理、陪玩者资料库、预约匹配、实时通讯、支付结算、安全隐私保护、客户服务及数据分析等功能,打造综合性社交平台。随着互联网技术发展,陪玩系统正成为游戏爱好者的新宠,改变游戏体验并带来新的商业模式。
|
2月前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
96 2

推荐镜像

更多