如何实现SCTP多归属链路对接

简介: 最近完成了贝尔及华为软交换的SCTP 多归属链路对接。由于网络上对于多归属链路介绍的资料特别少。能看到的一些资料介绍,但是说明的不详细,大都是Demo性质不能完全商用。以客户端为例子,概括如下,首先绑定本端两个IP,然后绑定交换的主用Path。然后将该主用的Path的IP设置为PrimaryPath。如果对端交换不支持BEAT心跳消息,就不要发送该BEAT消息。 现在分享下我的具体的经验心得。

前言


最近完成了贝尔及华为软交换的SCTP 多归属链路对接。由于网络上对于多归属链路介绍的资料特别少。能看到的一些资料介绍,但是说明的不详细,大都是Demo性质不能完全商用。以客户端为例子,概括如下,首先绑定本端两个IP,然后绑定交换的主用Path。然后将该主用的Path的IP设置为PrimaryPath。如果对端交换不支持BEAT心跳消息,就不要发送该BEAT消息。 现在分享下我的具体的经验心得。


提示:以下是本篇文章正文内容,下面案例可供参考



一、SCTP是什么?


SCTP (Stream Control Transmission Protocol)是一种传输协议,在TCP/IP协议栈中所处的位置和TCP、UDP类似,兼有TCP/UDP两者特征。


   随着网络接入技术的多样化,利用通信终端上多个网络接口实现并行多路径(Concurrent Multipath Transfer,CMT)成为研究的热点,成为提高数据传输效率重要手段。基于流传输(Stream Control Transmission Protocl,SCTP)实现的CMT是这一领域研究的重点,它通过扩展SCTP的多IP特性实现同一关联的多条端到端的路径上同时传输数据。    


   SIGTRAN信令通过SCTP建链承载信令。


   SCTP位于SCTP应用和无线分组网络(IP网)之间,通过两个SCTP端点之间建立关联,为两个SCTP用户提供可靠的消息传输业务。一个SCTP链路包换了一个或两个源/目的的地址。这些地址包含在每个端点的传输地址中。SCTP的关联结构如图1所示。


12ffde058fc54e3baa799cb3b39417be.png


   SCTP发送端使用一组传输地址作为消息的目的地,会根据SCTP用户的指令和当前合法的目的地址集合的可达性状态,为每个待发送的消息选择一个目的传输地址。在关联建立后,需要为每个SCTP端点定义一条主路径,用来在正常情况下发送SCTP消息。正常情况下,SCTP只选择其中的一条可用路径作为主路径传输数据,其他路径作为备用路径。当主路径失效时,SCTP切换到其中的一条备用路径上继续传输。




二、lksctp


lksctp封装了linux内核sctp的接口函数。使用lksctp可以加速sctp的开发。代码中引入sctp.h,编译时加入-lsctp,进行动态库链接。







三.sctp初始化


from_sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_SCTP);
setsockopt(from_sockfd,SOL_SOCKET,SO_SNDBUF,(char*)&sndBufS,sndBufL);
setsockopt(from_sockfd,SOL_SOCKET,SO_RCVBUF,(char*)&rcvBufS,rcvBufL);
setsockopt(from_sockfd, SOL_SOCKET, SO_REUSEADDR, &reuse_address, sizeof(reuse_address);
setsockopt(from_sockfd , IPPROTO_SCTP  , SCTP_RTOINFO  , &timeout , opt_len);
setsockopt(from_sockfd , IPPROTO_SCTP , SCTP_ASSOCINFO  , &assocmaxrxt   , opt_len);
setsockopt(from_sockfd, IPPROTO_SCTP, SCTP_INITMSG, &initmsg, sizeof(initmsg);


四.绑定本端两个IP


  struct sockaddr_in cliaddr;
  int ret;  
  bzero( (void *)&cliaddr, sizeof(cliaddr) );
  cliaddr.sin_family = AF_INET; 
  cliaddr.sin_addr.s_addr = pFrom_addr[0].sin_addr.s_addr;
  cliaddr.sin_port = pFrom_addr[0].sin_port;
  ret = bind(fd, (struct sockaddr *)&cliaddr, sizeof(cliaddr));
   bzero( (void *)&cliaddr, sizeof(cliaddr) );
   cliaddr.sin_family = AF_INET;
   cliaddr.sin_addr.s_addr = pFrom_addr[1].sin_addr.s_addr;
   cliaddr.sin_port = pFrom_addr[1].sin_port;
   ret = sctp_bindx(fd, (struct sockaddr *)&cliaddr, 1, SCTP_BINDX_ADD_ADDR);


五.与对端建链


设置对端两个IP


 if (sctp_peeraddr->addr_num) 
  {
     addr = (struct sockaddr *)(cli_addr + offsetof(struct sctp_getaddrs, addrs));
     for (index = 0; index < sctp_peeraddr->addr_num; index++) 
     {
        memset(dest, 0, sizeof(dest));
        if (addr->sa_family == AF_INET) 
        {
          //Log::PrintLog(LOG_INFO, "[SCTP_GET_PEER_ADDRS] %s\n", inet_ntoa(((struct sockaddr_in *)addr)->sin_addr));
          Log::PrintLog(LOG_TRACE, "Sctp.cxx", "sctp_peer_param()", "[SCTP_GET_PEER_ADDRS %s]",inet_ntoa(((struct sockaddr_in *)addr)->sin_addr));
          memcpy(&paddrparams.spp_address, addr, sizeof(struct sockaddr_in));
          addr = (struct sockaddr *) (((char *) addr) + sizeof(struct sockaddr_in));
        }
        ret = setsockopt(cfd, IPPROTO_SCTP, SCTP_PEER_ADDR_PARAMS, (const void *)&paddrparams, sizeof(paddrparams));
        if (ret < 0) 
        {
          //Log::PrintLog(LOG_INFO,"[set SCTP_PEER_ADDR_PARAMS error] %d:%s\n", errno, strerror(errno));
          Log::PrintLog(LOG_TRACE, "Sctp.cxx", "sctp_peer_param()", "[SCTP_PEER_ADDR_PARAMS err] %d %s", errno, strerror(errno));
          return;
        }
        Log::PrintLog(LOG_TRACE, "Sctp.cxx", "sctp_peer_param()", "set SCTP_PEER_ADDR_PARAMS]");
        Log::PrintLog(LOG_TRACE, "Sctp.cxx", "sctp_peer_param()", "get SCTP_PEER_ADDR_PARAMS] hb = %d, sackdelay = %d, %s, %s, %s",
         paddrparams.spp_hbinterval,
         paddrparams.spp_sackdelay,
         (paddrparams.spp_flags & SPP_HB_ENABLE)?"HB_ENABLE":"HB_DISABLE",
         (paddrparams.spp_flags & SPP_PMTUD_ENABLE)?"PMTUD_ENABLE":"PMTUD_DISABLE",
         (paddrparams.spp_flags & SPP_SACKDELAY_ENABLE)?"SACKDELAY_ENABLE":"SACKDELAY_DISABLE");
   }
  }


与一个IP建链:


sctp_connectx(from_sockfd, (struct sockaddr*)&m_primsockaddr, 1,(sctp_assoc_t *)&m_assoc[0];


切记,与对端建联时,初始时,只和一个IP进行建链。


六.设置主要路径


setsockopt(from_sockfd,IPPROTO_SCTP,SCTP_PRIMARY_ADDR,&m_primaddr,sizeof(m_primaddr)


七.设置是否启用心跳


struct sctp_paddrparams paddrparams;
 if (spp_hbinterval == 0) 
  {
   paddrparams.spp_flags |= SPP_HB_DISABLE;
  } 
  else 
  {
   paddrparams.spp_flags |= SPP_HB_ENABLE;
   paddrparams.spp_hbinterval = spp_hbinterval;
  }
ret = setsockopt(cfd, IPPROTO_SCTP, SCTP_PEER_ADDR_PARAMS, (const void *)&paddrparams, sizeof(paddrparams));


八.关于防火墙的配置


如果系统的网卡地址是通过防火墙映射的,防火墙上有的没有SCTP一个选项,那么配置TCP即可。但是防火墙一定要设置为透明模式。不然在调试多归属链路时会遇到各式各样的怪问题。


总结


SCTP偶链多归属对接,网上资料特别少,有的也是语焉不详。笔者根据最近数月的调试,将经验分享处理,希望对进行SIGTRAN信令开始的同行有帮助。

相关文章
|
9月前
|
API 数据安全/隐私保护
基于协议的业务模块路由管理
关于业务模块与路由权限的管理方案
54 0
|
11月前
|
缓存 算法
软交换网络的通信流程
软交换网络的通信流程
EMQ
|
网络协议 中间件 物联网
QUIC 多流桥接、新增 DDS 协议转换代理
即将发布的超轻量 MQTT Broker NanoMQ 0.16为用户提供了2个重要新功能:MQTT over QUIC的多流桥接和DDS协议转换代理,拓宽了其弱网桥接传输性能和在边缘端的使用场景。
EMQ
266 0
QUIC 多流桥接、新增 DDS 协议转换代理
|
网络协议 中间件 Linux
SOME/IP概述2【SOME/IP的主要中间件功能+SOME/IP报文PDU的封装】
SOME/IP概述2【SOME/IP的主要中间件功能+SOME/IP报文PDU的封装】
SOME/IP概述2【SOME/IP的主要中间件功能+SOME/IP报文PDU的封装】
|
数据格式 UED 网络架构
一对一直播系统源码,影响数据传输的网络七层结构
一对一直播系统源码,影响数据传输的网络七层结构
|
存储 测试技术 数据库
基于RPC接口的业务侧流量回放
在产品需求迭代过程中,功能测试与回归测试是必不可少的两个环节。对于改动较大的项目,首先,确保功能的实现符合产品逻辑并做到100%没有问题离不开有效的功能测试;其次,项目中很多逻辑的改动都是在原有功能的基础上进行的,这时候就需要一定的回归测试。通常,在功能测试时,人工case不能模拟线上用户的所有行为,且具有一定的主观性;回归测试时,采用全面回归的方式往往也伴随着测试成本的增加。一个好的方式就是利用线上流量来验证。
272 0
|
内存技术
中继接口信令配合
中继接口电路的基本功能已如前述,也可选用合适的集成片予以实现。中继接口的信令配合是一个重要问题,这里着重加以说明。记发器信号通常采用MFC,如与步进制配合也可采用直流脉冲。线路信令有直流标志信令、带内单频脉冲信令和数字型线路信令方式。以下主要就较复杂的线路信令的配合,分别几种情况说明如下。
|
运维 安全 网络协议
SOFAGW 网关:安全可信的跨域 RPC/消息 互通解决方案
本文将介绍 SOFAGW 互通网关,首先切入在跨站点通信时碰到的核心痛点,引入 SOFAGW 互通网关的解决方案,会重点说明如何解决在安全、互通、接入成本、高效等几方面问题,介绍 SOFAGW 网关的内部实现架构,展示 SOFAGW 网关达成的业务成果。
SOFAGW 网关:安全可信的跨域 RPC/消息 互通解决方案
|
消息中间件 存储 负载均衡
极速同步:网关间多点协同实现数据共享最佳实践
背景 网关网关提供了从OSS到NAS协议转换,依托于OSS的稳定性和经济性,降低了用户的使用成本,又具备了传统NAS的易用性和POSIX兼容性,可以与用户的已有应用无缝对接,满足了中小企业客户的需求。
1450 0
极速同步:网关间多点协同实现数据共享最佳实践