Turn Client 和 Server交互简单流程

2024-05-27 09:32

本文主要是介绍Turn Client 和 Server交互简单流程,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

  • 1简介
  • 2 报文结构
    • 2.1 Message Header
      • 2.1.1 头部2bits
      • 2.1.2 Stun Message Type
      • 2.1.3 Message Length
      • 2.1.4 Magic Cookie
      • 2.1.5 Transaction ID (96bits)
    • 2.2 Stun Attributes
      • 2.2.1 Type
      • 2.2.2 Length
      • 2.2.3 Value
        • 2.2.3.1 MAPPED-ADDRESS
        • 2.2.3.2 XOR-MAPPED-ADDRESS
        • 2.2.3.3 USERNAME
        • 2.2.3.4 MESSAGE-INTEGRITY
        • 2.2.3.5 REALM
        • 2.2.3.6 NONCE
        • 2.2.3.7 ERROR-CODE
  • 3 分配
    • 3.1 Client ---> Server Allocate
    • 3.2 Server ---> Client Error
    • 3.3 Client ---> Server Allocate
    • 3.4 Server ---> Client Success
  • 4 刷新
    • 4.1 Client ---> Server Refresh
    • 4.2 Server ---> Client Success
  • 5 CreatePermission
    • 5.1 Client ---> Server CreatePermission
    • 5.2 Server ---> Client Success
  • 6 连接Peer
    • 6.1 Server ---> Client ConnectionAttempt
    • 6.2 Client ---> Server ConnectionBind
    • 6.3 Server --->Client Error
    • 6.4 Client ---> Server ConnectionBind
    • 6.5 Server --->Client Success
  • 7 一些记录
    • 7.1 多路复用时候,如何判断是Turn包?

参考文章:
1.RFC3489
https://www.rfc-editor.org/info/rfc3489
2.RFC5389
https://www.rfc-editor.org/info/rfc5389
3.RFC5766
https://www.rfc-editor.org/rfc/rfc5766.html
4.RFC6062
https://www.rfc-editor.org/rfc/rfc6062.html
5.P2P通信标准协议(一)之Stun
https://www.cnblogs.com/pannengzhi/p/5041546.html
6.P2P通信标准协议(二)之Turn
https://www.cnblogs.com/pannengzhi/p/5048965.html

1简介

前面的参考文章详细介绍了Turn的定义、结构以及流程。

Turn Client和Turn Server简单流程描述如下:Turn Client的内网IP:PORT(A1),通过路由的公网IP:PORT(A2), 通过Turn命令向Turn Server IP:PORT(B1) 创建ALLOCATION。Turn serve随后会给Turn Client分配一个中继地址IP:PORT(B2)。若Peer要向这个Turn Client发送数据,只要直接向这个Turn Client的中继地址B2发送数据即可,然后Turn Server会把发给B2的数据转发给A2。

Turn Client和Turn Server通信以及通过中继转发数据时候可以使用UDP/TCP/TLS over TCP。但是,Turn Server和Peer通信是基于UDP的,所以若Turn Client和Turn Server通过TCP进行交互,会在Turn Server端进行协议转换,RFC5766中画图如下:
在这里插入图片描述

2 报文结构

在开始分析Client 和 Server 交互流程之前,需要先对Turn的报文结构做个简单梳理,Turn是Stun的一个扩展,所以Turn的报文结构遵循Stun的报文结构规范。

2.1 Message Header

所有的Turn 报文都有20个字节的头部信息,并且采用大端模式。
在RFC3489中,头部结构如下:
在这里插入图片描述
在RFC5389中,为了兼容RFC3489,将头部结构定义如下:
在这里插入图片描述

2.1.1 头部2bits

在上面头部的两个字节必须为0。

2.1.2 Stun Message Type

关于Message Type,在RFC8389中描述如下:

消息类型定义了Stun消息的消息类别(请求,成功响应,失败响应或指示)和消息方法(主要功能)。 尽管有四种消息类别,但Stun中只有两种事务类型:请求/响应事务(由请求消息和响应消息组成)和指示事务(由单个指示消息组成)。 响应类别分为错误响应和成功响应,以帮助快速处理Stun消息。

这个字段又可以分为如下结构:
在这里插入图片描述
可以看到上面有M0 ~ M11 C0 ~ C1这两种类型。
M0 ~ M11代表 message type,而C0 ~ C11代表message class。
message class有如下定义:

0b00:   Requeset
0b01:   Indication
0b10:   Success response
0b11:   Error response

message type 有如下定义:

0x003 :  Allocate          (only request/response semantics defined)
0x004 :  Refresh           (only request/response semantics defined)
0x006 :  Send              (only indication semantics defined)
0x007 :  Data              (only indication semantics defined)
0x008 :  CreatePermission  (only request/response semantics defined
0x009 :  ChannelBind       (only request/response semantics defined)

2.1.3 Message Length

message length 表示信息的长度,不包含20字节的头部。另外,Stun的属性都为4字节对齐,因此最后两位始终为0。

2.1.4 Magic Cookie

固定为0x2112A442。

2.1.5 Transaction ID (96bits)

是一个96个字节的标识符,用于区分Stun传输事务。详细介绍见RFC5389。

2.2 Stun Attributes

在头部之后,会有0个或多个Stun属性。每一个Stun属性必须是TLV结构。
T:Type 16bit L:Length 16bit V:Value 32bit对齐, 结构图如下:
在这里插入图片描述

2.2.1 Type

属性的类型,0x0000-0x7FFF之间的属性被指定为强制理解,意思是Stun终端必须要理解此属性,否则将返回错误信息;而0x8000-0xFFFF之间的属性为选择性理解,即如果Stun终端不识别此属性则将其忽略。
Type部分取值如下:

0x0000: (Reserved)
0x0001: MAPPED-ADDRESS
0x0002: (Reserved; was RESPONSE-ADDRESS)
0x0003: (Reserved; was CHANGE-ADDRESS)
0x0004: (Reserved; was SOURCE-ADDRESS)
0x0005: (Reserved; was CHANGED-ADDRESS)
0x0006: USERNAME
0x0007: (Reserved; was PASSWORD)
0x0008: MESSAGE-INTEGRITY
0x0009: ERROR-CODE
0x000A: UNKNOWN-ATTRIBUTES
0x000B: (Reserved; was REFLECTED-FROM)
0x0014: REALM
0x0015: NONCE
0x0020: XOR-MAPPED-ADDRESS
0x8022: SOFTWARE
0x8023: ALTERNATE-Server
0x8028: FINGERPRINT

2.2.2 Length

value的长度,因为是4字节对齐,所以若属性的长度不是4字节,会被补数据,而长度也会加上补数据的长度,所以最终长度一定是4字节的倍数。

2.2.3 Value

下面几个是比较常见的(不做详细介绍,详细介绍见RFC5389):

2.2.3.1 MAPPED-ADDRESS

结构如下:
在这里插入图片描述
Family表示使用的是IPv4(0x01)或者IPv6(0x02)
Port表示端口号
Address表示IP地址

2.2.3.2 XOR-MAPPED-ADDRESS

结构如下:
在这里插入图片描述
和上面的MAPPED-ADDRESS类似,只不过将Port和Address进行了异或。

2.2.3.3 USERNAME

用于message integrity,它标识在message integrity检查中使用的用户名和密码组合。

2.2.3.4 MESSAGE-INTEGRITY

message integrity可以出现在任何Stun消息类型中。它是由 username:realm:password进行MD5加密得到的数据。

2.2.3.5 REALM

可以出现在请求和响应中,在请求中存在REALM属性表示正在使用长期凭证进行身份验证。

2.2.3.6 NONCE

可以出现在请求和响应中,是由服务器创建的。

2.2.3.7 ERROR-CODE

用于error response报文中。其包含了300-699表示的错误代码,以及一个UTF-8格式的文字出错信息,部分错误类型如下:

300:  尝试替代
400:  错误请求
401:  未授权
420:  未知属性
438:  过期Nonce
500:  服务器错误

下面对Turn Server和Turn Client整个交互过程做个简单分析。

3 分配

Client会向Server发送allocate请求,但是没有携带验证信息,Server会返回error信息。然后,Client会解析error信息中的有效信息,添加进验证信息中,再次给Server发送allocate请求,Server解析到验证信息并进行验证,会返回成功信息。所以, Client会向Server发送两次allocate请求。
流程如下:
在这里插入图片描述
抓取的包如下:
在这里插入图片描述

3.1 Client —> Server Allocate

报文如下:
在这里插入图片描述
Client使用TCP和Server通信,从上面可以看到,Client第一次向Server发送allocate请求,没有携带任何的Stun属性,只是携带了头部信息,并且type值为0x03。

3.2 Server —> Client Error

报文如下:
在这里插入图片描述
Server返回401错误,并返回了几个Turn属性,其中我们需要使用NONCE再次向Server发送allocate请求。

同时,需要注意服务器返回的头部信息中的Transaction ID和Client发送出去的一致。

3.3 Client —> Server Allocate

报文如下:
在这里插入图片描述
Client再次向Server发送allocate请求,并携带一些Stun属性信息。NONCE为Server上次传递过来的。

3.4 Server —> Client Success

报文如下:
在这里插入图片描述
在Server返回的报文信息中,XOR-RELAYED-ADDRESS表示的Client的路由公网IP:PORT(A2),XOR-MAPPED-ADDRESS表示的是Server为Client分配的中继地址IP:PORT(B2)。

至此,Client已经申请到了中继地址。

4 刷新

在上面的3.3 和 3.4中,我们可以看到有个字段:LIFETIME。
这个属性标识在没有刷新情况下Server将维持分配的持续时间,单位为秒。若在这个时间之内,Client没有向Server发送refresh请求,那么Client被分配的IP:PORT将会被回收,因此我们需要定时在LIFETIME之内向Server发送refresh请求。
流程如下:
在这里插入图片描述
报文如下:
在这里插入图片描述

4.1 Client —> Server Refresh

报文如下:
在这里插入图片描述
在上面的报文中,Client向Server发出了refersh请求,刷新时间是600s。

4.2 Server —> Client Success

报文如下:
在这里插入图片描述
Server返回成功,并且给出LIFETIME为300s。

5 CreatePermission

在RFC5766中,Send Mechanism章节介绍到,当Client发送数据给Server时候,如果Client的Send indications没有被验证, 会被Server当做攻击,这些数据会被丢弃。因此在向Server发送数据前,先向Server发送CreatePermission 请求,请求中包含了要发送的Peer的IP地址。

如下,如果Client没有向Server发送Peer B的CreatePermission 请求,数据就会被丢弃。
在这里插入图片描述
报文如下:
在这里插入图片描述

5.1 Client —> Server CreatePermission

报文如下:
在这里插入图片描述
上面报文的XOR-Peer-ADDRESS便是Client要发送Peer的IP地址。

5.2 Server —> Client Success

报文如下:
在这里插入图片描述
Server返回成功。

6 连接Peer

当Client向Server 发送allocate请求成功后,并且定时进行refresh。此时,Client就会等待Server发送Peer的信息,然后Client会向Server发送ConnectionBind请求,和Peer建立连接,然后就可以正常和Peer进行通信。

注意:以下的流程,只是根据测试现象得出的,可能有些服务器因为功能不同或者参考的RFC不同导致交互和下面的不一致,下面的仅供参考

在RFC6062中,这样描述:

Server成功处理了分配请求后,当一个Peer和Client的中继地址建立连接时,Client都会接收Server发送的ConnectionAttempt indication。这个indication包含了CONNECTION-ID和XOR-Peer-ADDRESS属性。如果Client希望接收这个连接,就会重新创建一个新的socket,和Server建立新的连接,并使用新的socket向Server发送ConnectionBind请求,这个请求包含了Server发送ConnectionAttempt 时候的CONNECTION-ID。

后续Client和Peer通信都会使用新的socket,而原有的socket则会继续等待新的Peer连接,等到Server的ConnectionAttempt indication。

报文如下:
在这里插入图片描述

6.1 Server —> Client ConnectionAttempt

报文如下:
在这里插入图片描述
Server发送过来的请求携带了CONNECTION-ID和XOR-Peer-ADDRESS这两个重要的属性。

6.2 Client —> Server ConnectionBind

报文如下:
在这里插入图片描述
上面的报文中,SRC PORT是8507,和以前的端口不一致,说明Client已经使用新的socket向Server发送ConnectionBind请求,并且携带了一些必要的属性。

6.3 Server —>Client Error

在这里插入图片描述
由于是新的连接,使用的NONCE为原有的NONCE,服务器可能会返回401,并且携带新的NONCE。

6.4 Client —> Server ConnectionBind

报文如下:
在这里插入图片描述
Client使用新的NONCE重新向Server发送ConnectionBind请求。

6.5 Server —>Client Success

报文如下:
在这里插入图片描述
服务器返回success请求。

至此,Client已经和Peer建立了连接,后续就可以使用这个新的socket进行数据收发。

7 一些记录

7.1 多路复用时候,如何判断是Turn包?

可以通过以下进行判断
Turn头部最高两位必需是0;
Turn头部的Magic Cookie 为固定值;
Turn头部的Message Length以字节为单位,因为所有的Stun是4字节对齐的,所以这个字段的最后两位恒等于0。

这篇关于Turn Client 和 Server交互简单流程的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1007091

相关文章

Window Server创建2台服务器的故障转移群集的图文教程

《WindowServer创建2台服务器的故障转移群集的图文教程》本文主要介绍了在WindowsServer系统上创建一个包含两台成员服务器的故障转移群集,文中通过图文示例介绍的非常详细,对大家的... 目录一、 准备条件二、在ServerB安装故障转移群集三、在ServerC安装故障转移群集,操作与Ser

使用MongoDB进行数据存储的操作流程

《使用MongoDB进行数据存储的操作流程》在现代应用开发中,数据存储是一个至关重要的部分,随着数据量的增大和复杂性的增加,传统的关系型数据库有时难以应对高并发和大数据量的处理需求,MongoDB作为... 目录什么是MongoDB?MongoDB的优势使用MongoDB进行数据存储1. 安装MongoDB

利用Python编写一个简单的聊天机器人

《利用Python编写一个简单的聊天机器人》这篇文章主要为大家详细介绍了如何利用Python编写一个简单的聊天机器人,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 使用 python 编写一个简单的聊天机器人可以从最基础的逻辑开始,然后逐步加入更复杂的功能。这里我们将先实现一个简单的

基于WinForm+Halcon实现图像缩放与交互功能

《基于WinForm+Halcon实现图像缩放与交互功能》本文主要讲述在WinForm中结合Halcon实现图像缩放、平移及实时显示灰度值等交互功能,包括初始化窗口的不同方式,以及通过特定事件添加相应... 目录前言初始化窗口添加图像缩放功能添加图像平移功能添加实时显示灰度值功能示例代码总结最后前言本文将

Python实现NLP的完整流程介绍

《Python实现NLP的完整流程介绍》这篇文章主要为大家详细介绍了Python实现NLP的完整流程,文中的示例代码讲解详细,具有一定的借鉴价值,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1. 编程安装和导入必要的库2. 文本数据准备3. 文本预处理3.1 小写化3.2 分词(Tokenizatio

使用IntelliJ IDEA创建简单的Java Web项目完整步骤

《使用IntelliJIDEA创建简单的JavaWeb项目完整步骤》:本文主要介绍如何使用IntelliJIDEA创建一个简单的JavaWeb项目,实现登录、注册和查看用户列表功能,使用Se... 目录前置准备项目功能实现步骤1. 创建项目2. 配置 Tomcat3. 项目文件结构4. 创建数据库和表5.

使用PyQt5编写一个简单的取色器

《使用PyQt5编写一个简单的取色器》:本文主要介绍PyQt5搭建的一个取色器,一共写了两款应用,一款使用快捷键捕获鼠标附近图像的RGB和16进制颜色编码,一款跟随鼠标刷新图像的RGB和16... 目录取色器1取色器2PyQt5搭建的一个取色器,一共写了两款应用,一款使用快捷键捕获鼠标附近图像的RGB和16

四种简单方法 轻松进入电脑主板 BIOS 或 UEFI 固件设置

《四种简单方法轻松进入电脑主板BIOS或UEFI固件设置》设置BIOS/UEFI是计算机维护和管理中的一项重要任务,它允许用户配置计算机的启动选项、硬件设置和其他关键参数,该怎么进入呢?下面... 随着计算机技术的发展,大多数主流 PC 和笔记本已经从传统 BIOS 转向了 UEFI 固件。很多时候,我们也

基于Qt开发一个简单的OFD阅读器

《基于Qt开发一个简单的OFD阅读器》这篇文章主要为大家详细介绍了如何使用Qt框架开发一个功能强大且性能优异的OFD阅读器,文中的示例代码讲解详细,有需要的小伙伴可以参考一下... 目录摘要引言一、OFD文件格式解析二、文档结构解析三、页面渲染四、用户交互五、性能优化六、示例代码七、未来发展方向八、结论摘要

SpringBoot使用minio进行文件管理的流程步骤

《SpringBoot使用minio进行文件管理的流程步骤》MinIO是一个高性能的对象存储系统,兼容AmazonS3API,该软件设计用于处理非结构化数据,如图片、视频、日志文件以及备份数据等,本文... 目录一、拉取minio镜像二、创建配置文件和上传文件的目录三、启动容器四、浏览器登录 minio五、