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

相关文章

Security OAuth2 单点登录流程

单点登录(英语:Single sign-on,缩写为 SSO),又译为单一签入,一种对于许多相互关连,但是又是各自独立的软件系统,提供访问控制的属性。当拥有这项属性时,当用户登录时,就可以获取所有系统的访问权限,不用对每个单一系统都逐一登录。这项功能通常是以轻型目录访问协议(LDAP)来实现,在服务器上会将用户信息存储到LDAP数据库中。相同的,单一注销(single sign-off)就是指

Spring Security基于数据库验证流程详解

Spring Security 校验流程图 相关解释说明(认真看哦) AbstractAuthenticationProcessingFilter 抽象类 /*** 调用 #requiresAuthentication(HttpServletRequest, HttpServletResponse) 决定是否需要进行验证操作。* 如果需要验证,则会调用 #attemptAuthentica

csu 1446 Problem J Modified LCS (扩展欧几里得算法的简单应用)

这是一道扩展欧几里得算法的简单应用题,这题是在湖南多校训练赛中队友ac的一道题,在比赛之后请教了队友,然后自己把它a掉 这也是自己独自做扩展欧几里得算法的题目 题意:把题意转变下就变成了:求d1*x - d2*y = f2 - f1的解,很明显用exgcd来解 下面介绍一下exgcd的一些知识点:求ax + by = c的解 一、首先求ax + by = gcd(a,b)的解 这个

hdu2289(简单二分)

虽说是简单二分,但是我还是wa死了  题意:已知圆台的体积,求高度 首先要知道圆台体积怎么求:设上下底的半径分别为r1,r2,高为h,V = PI*(r1*r1+r1*r2+r2*r2)*h/3 然后以h进行二分 代码如下: #include<iostream>#include<algorithm>#include<cstring>#include<stack>#includ

usaco 1.3 Prime Cryptarithm(简单哈希表暴搜剪枝)

思路: 1. 用一个 hash[ ] 数组存放输入的数字,令 hash[ tmp ]=1 。 2. 一个自定义函数 check( ) ,检查各位是否为输入的数字。 3. 暴搜。第一行数从 100到999,第二行数从 10到99。 4. 剪枝。 代码: /*ID: who jayLANG: C++TASK: crypt1*/#include<stdio.h>bool h

uva 10387 Billiard(简单几何)

题意是一个球从矩形的中点出发,告诉你小球与矩形两条边的碰撞次数与小球回到原点的时间,求小球出发时的角度和小球的速度。 简单的几何问题,小球每与竖边碰撞一次,向右扩展一个相同的矩形;每与横边碰撞一次,向上扩展一个相同的矩形。 可以发现,扩展矩形的路径和在当前矩形中的每一段路径相同,当小球回到出发点时,一条直线的路径刚好经过最后一个扩展矩形的中心点。 最后扩展的路径和横边竖边恰好组成一个直

poj 1113 凸包+简单几何计算

题意: 给N个平面上的点,现在要在离点外L米处建城墙,使得城墙把所有点都包含进去且城墙的长度最短。 解析: 韬哥出的某次训练赛上A出的第一道计算几何,算是大水题吧。 用convexhull算法把凸包求出来,然后加加减减就A了。 计算见下图: 好久没玩画图了啊好开心。 代码: #include <iostream>#include <cstdio>#inclu

uva 10130 简单背包

题意: 背包和 代码: #include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstring>#include <cmath>#include <stack>#include <vector>#include <queue>#include <map>

kubelet组件的启动流程源码分析

概述 摘要: 本文将总结kubelet的作用以及原理,在有一定基础认识的前提下,通过阅读kubelet源码,对kubelet组件的启动流程进行分析。 正文 kubelet的作用 这里对kubelet的作用做一个简单总结。 节点管理 节点的注册 节点状态更新 容器管理(pod生命周期管理) 监听apiserver的容器事件 容器的创建、删除(CRI) 容器的网络的创建与删除

JAVA用最简单的方法来构建一个高可用的服务端,提升系统可用性

一、什么是提升系统的高可用性 JAVA服务端,顾名思义就是23体验网为用户提供服务的。停工时间,就是不能向用户提供服务的时间。高可用,就是系统具有高度可用性,尽量减少停工时间。如何用最简单的方法来搭建一个高效率可用的服务端JAVA呢? 停工的原因一般有: 服务器故障。例如服务器宕机,服务器网络出现问题,机房或者机架出现问题等;访问量急剧上升,导致服务器压力过大导致访问量急剧上升的原因;时间和