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

相关文章

SpringMVC 通过ajax 前后端数据交互的实现方法

《SpringMVC通过ajax前后端数据交互的实现方法》:本文主要介绍SpringMVC通过ajax前后端数据交互的实现方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价... 在前端的开发过程中,经常在html页面通过AJAX进行前后端数据的交互,SpringMVC的controll

Spring Boot 整合 SSE的高级实践(Server-Sent Events)

《SpringBoot整合SSE的高级实践(Server-SentEvents)》SSE(Server-SentEvents)是一种基于HTTP协议的单向通信机制,允许服务器向浏览器持续发送实... 目录1、简述2、Spring Boot 中的SSE实现2.1 添加依赖2.2 实现后端接口2.3 配置超时时

将Java项目提交到云服务器的流程步骤

《将Java项目提交到云服务器的流程步骤》所谓将项目提交到云服务器即将你的项目打成一个jar包然后提交到云服务器即可,因此我们需要准备服务器环境为:Linux+JDK+MariDB(MySQL)+Gi... 目录1. 安装 jdk1.1 查看 jdk 版本1.2 下载 jdk2. 安装 mariadb(my

SQL server配置管理器找不到如何打开它

《SQLserver配置管理器找不到如何打开它》最近遇到了SQLserver配置管理器打不开的问题,尝试在开始菜单栏搜SQLServerManager无果,于是将自己找到的方法总结分享给大家,对SQ... 目录方法一:桌面图标进入方法二:运行窗口进入方法三:查找文件路径方法四:检查 SQL Server 安

python连接本地SQL server详细图文教程

《python连接本地SQLserver详细图文教程》在数据分析领域,经常需要从数据库中获取数据进行分析和处理,下面:本文主要介绍python连接本地SQLserver的相关资料,文中通过代码... 目录一.设置本地账号1.新建用户2.开启双重验证3,开启TCP/IP本地服务二js.python连接实例1.

Feign Client超时时间设置不生效的解决方法

《FeignClient超时时间设置不生效的解决方法》这篇文章主要为大家详细介绍了FeignClient超时时间设置不生效的原因与解决方法,具有一定的的参考价值,希望对大家有一定的帮助... 在使用Feign Client时,可以通过两种方式来设置超时时间:1.针对整个Feign Client设置超时时间

使用Python开发一个简单的本地图片服务器

《使用Python开发一个简单的本地图片服务器》本文介绍了如何结合wxPython构建的图形用户界面GUI和Python内建的Web服务器功能,在本地网络中搭建一个私人的,即开即用的网页相册,文中的示... 目录项目目标核心技术栈代码深度解析完整代码工作流程主要功能与优势潜在改进与思考运行结果总结你是否曾经

Mysql表的简单操作(基本技能)

《Mysql表的简单操作(基本技能)》在数据库中,表的操作主要包括表的创建、查看、修改、删除等,了解如何操作这些表是数据库管理和开发的基本技能,本文给大家介绍Mysql表的简单操作,感兴趣的朋友一起看... 目录3.1 创建表 3.2 查看表结构3.3 修改表3.4 实践案例:修改表在数据库中,表的操作主要

springboot简单集成Security配置的教程

《springboot简单集成Security配置的教程》:本文主要介绍springboot简单集成Security配置的教程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,... 目录集成Security安全框架引入依赖编写配置类WebSecurityConfig(自定义资源权限规则

mysql出现ERROR 2003 (HY000): Can‘t connect to MySQL server on ‘localhost‘ (10061)的解决方法

《mysql出现ERROR2003(HY000):Can‘tconnecttoMySQLserveron‘localhost‘(10061)的解决方法》本文主要介绍了mysql出现... 目录前言:第一步:第二步:第三步:总结:前言:当你想通过命令窗口想打开mysql时候发现提http://www.cpp