成功扩展live555支持ipv6,同时支持RTSPServer & RTSPClient
live555对ipv6的扩展
从live555的官网看live555的发展历史,实在是历史悠久,保守估计已经发展了至少16年以上了,同时,这也导致了live555在很多架构和考虑上面不能满足现代化的多线程、ipv6方面的需求,虽然官方也开启了对ipv6功能支持的众筹,但是已经很久了,预计很长时间内是不会有这个计划支持了,因为要改动的地方还真是蛮多的:
,在上一期中我们已经为live555的多线程开了个头《经过两个多月的攻关,终于搞定了live555多线程并稳定压测通过》,今天我们要来聊一下我们在live555扩展IPv6方面是怎么做到的!
设计过程
IPV4 地址
rtsp://192.168.1.100:554/ch1 
rtsp://admin:12345@192.168.1.100:554/ch1
IPV6 地址
rtsp://[2001:0:9d38:953c:38b0:d177:88d8:a5e0]:554/ch1 
rtsp://admin:12345@[2001:0:9d38:953c:38b0:d177:88d8:a5e0]:554/ch1
支持IPv6修改步骤
增加live_ipv4_ipv6.h和live_ipv4_ipv6.cpp两个文件
用途: 在live所有用到类型为netAddressBits的文件中,包含该头文件,针对ipv4和ipv6进行不同的处理;
live_ipv4_ipv6.h
#ifndef __LIVE_IPV4_IPV6
#define __LIVE_IPV4_IPV6
typedef enum LIVE_IPVER_ENUM
{
    LIVE_IP_VER_4   =   0,
    LIVE_IP_VER_6
}LIVE_IP_VER_ENUM;
extern LIVE_IP_VER_ENUM live_ip_ver;
#endif
live_ipv4_ipv6.cpp
#include "live_ipv4_ipv6.h"
LIVE_IP_VER_ENUM live_ip_ver = LIVE_IP_VER_6;
NetAddress.hh
增加以下定义, 并注释掉typedef u_int32_t netAddressBits;
typedef struct __LIVE_NET_ADDRESS_INADDR
{
    struct in_addr sin_addr;
    struct in6_addr sin6_addr;
    __LIVE_NET_ADDRESS_INADDR()
    {
        sin_addr.s_addr = INADDR_ANY;
        sin6_addr = in6addr_any;
    };
}LIVE_NET_ADDRESS_INADDR;
//typedef u_int32_t netAddressBits; //注释掉该句,在所有用到netAddressBits的地方,均用LIVE_NET_ADDRESS_INADDR替代;
//增加以下定义
typedef struct __LIVE_NET_ADDRESS_SOCKADDR_IN
{
    struct sockaddr_in  saddr4;
    struct sockaddr_in6 saddr6;
}LIVE_NET_ADDRESS_SOCKADDR_IN;
将所有struct in_addr 改为 LIVE_NET_ADDRESS, 除了以下几处: 
    void AddressString::init(struct in_addr addr)
将所有struct sockaddr_in 改为 LIVE_NET_ADDRESS_SOCKADDR_IN;
在EasyRtspClient中,将调用到LIVE_NET_ADDRESS_SOCKADDR_IN的函数,增加一个参数,用于标识是IPv4还是IPv6; 
从调用以下代码开始,进行区分,用于标识该客户端需要使用IPv4还是IPv6进行连接;
Boolean RTSPClient::parseRTSPURL(UsageEnvironment& env, char const* url,
                 char*& username, char*& password,
                 NetAddress& address,
                 portNumBits& portNum,
                 char const** urlSuffix) {
        do {
        // Parse the URL as "rtsp://[<username>[:<password>]@]<server-address-or-name>[:<port>][/<stream-name>]"
        char const* prefix = "rtsp://";
        unsigned const prefixLength = 7;
        if (_strncasecmp(url, prefix, prefixLength) != 0) {
            env.setResultMsg("URL is not of the form \"", prefix, "\"");
            break;
        }
        unsigned const parseBufferSize = 100;
        char parseBuffer[parseBufferSize] = {0};
        char const* from = &url[prefixLength];
        // Check whether "<username>[:<password>]@" occurs next.
        // We do this by checking whether '@' appears before the end of the URL, or before the first '/'.
        username = password = NULL; // default return values
        char const* colonPasswordStart = NULL;
        char const* p;
        //此处检查字符[
        for (p = from; *p != '\0' && *p != '/' && *p != '['; ++p) {
            if (*p == ':' && colonPasswordStart == NULL) {
        colonPasswordStart = p;
            } else if (*p == '@') {
        // We found <username> (and perhaps <password>).  Copy them into newly-allocated result strings:
        if (colonPasswordStart == NULL) colonPasswordStart = p;
        char const* usernameStart = from;
        unsigned usernameLen = colonPasswordStart - usernameStart;
        username = new char[usernameLen + 1] ; // allow for the trailing '\0'
        copyUsernameOrPasswordStringFromURL(username, usernameStart, usernameLen);
        char const* passwordStart = colonPasswordStart;
        if (passwordStart < p) ++passwordStart; // skip over the ':'
        unsigned passwordLen = p - passwordStart;
        password = new char[passwordLen + 1]; // allow for the trailing '\0'
        copyUsernameOrPasswordStringFromURL(password, passwordStart, passwordLen);
        from = p + 1; // skip over the '@'
        break;
            }
        }
        // Next, parse <server-address-or-name>
        char* to = &parseBuffer[0];
        unsigned i;
        live_ip_ver = LIVE_IP_VER_4;    //默认为IPv4
        if (*from == '[')       //如果地址是以符号[开头,则为IPv6  因为ipv6的地址是以符号[开头
        {
            live_ip_ver = LIVE_IP_VER_6;
        }
        if (live_ip_ver == LIVE_IP_VER_6)
        {
            *from ++;   //  跳过符号[
            for (i = 0; i < parseBufferSize; ++i) {
                if (*from == '\0' || *from == ']' || *from == '/') {
            // We've completed parsing the address
            *to = '\0';
            break;
                }
                *to++ = *from++;
            }
            if (i == parseBufferSize) {
                env.setResultMsg("URL is too long");
                break;
            }
            *from ++;       //  跳过符号]
        }
        else        //IPV4
        {
            for (i = 0; i < parseBufferSize; ++i) {
                if (*from == '\0' || *from == ':' || *from == '/') {
            // We've completed parsing the address
            *to = '\0';
            break;
                }
                *to++ = *from++;
            }
            if (i == parseBufferSize) {
                env.setResultMsg("URL is too long");
                break;
            }
        }
        //rtsp://[2001:0:9d38:953c:14b3:7a:3f57:fe40]:554/ch1
        //strcpy(parseBuffer, "2001:0:9d38:953c:38b0:d177:88d8:a5e0");
        NetAddressList addresses(parseBuffer);
        if (addresses.numAddresses() == 0) {
            env.setResultMsg("Failed to find network address for \"",
                    parseBuffer, "\"");
            break;
        }
        address = *(addresses.firstAddress());
        portNum = 554; // default value
        char nextChar = *from;
        if (nextChar == ':') {
            int portNumInt;
            if (sscanf(++from, "%d", &portNumInt) != 1) {
        env.setResultMsg("No port number follows ':'");
        break;
            }
            if (portNumInt < 1 || portNumInt > 65535) {
        env.setResultMsg("Bad port number");
        break;
            }
            portNum = (portNumBits)portNumInt;
            while (*from >= '0' && *from <= '9') ++from; // skip over port number
        }
        // The remainder of the URL is the suffix:
        if (urlSuffix != NULL) *urlSuffix = from;
        return True;
        } while (0);
  return False;
}
其中,  live_ip_ver 为全局变量,用于标识该IP地址类型; 
后面用到struct sockaddr_in 和 struct in_addr 的地方, 使用LIVE_NET_ADDRESS_SOCKADDR_IN来区分,并进行相应的处理;
live555中,就不能使用live_ip_ver这个全局变量了, 因为要同时兼容IPv4和IPv6, 将在下篇说明;
live555技术交流
邮件:289042893@qq.com
live555技术交流群:475947825
成功扩展live555支持ipv6,同时支持RTSPServer & RTSPClient的更多相关文章
- VC++ IPv6的支持
		
最近根据项目需要,要在产品中添加对IpV6的支持,因此研究了一下IPV6的相关内容,Ipv6 与原来最直观的改变就是地址结构的改变,IP地址由原来的32位扩展为128,这样原来的地址结构肯定就不够用了 ...
 - Azure Load Balancer : 支持 IPv6
		
越来越多的网站开始支持 IPv6,即使是哪些只提供 api 服务的站点也需要支持 IPv6,比如苹果应用商店中的 app 早就强制要求服务器端支持 IPv6 了.笔者在前文<Azure Load ...
 - iOS应用支持IPV6,就那点事儿
		
原文连接 果然是苹果打个哈欠,iOS行业内就得起一次风暴呀.自从5月初Apple明文规定所有开发者在6月1号以后提交新版本需要支持IPV6-Only的网络,大家便开始热火朝天的研究如何支持IPV6 ...
 - iOS应用支持IPV6
		
一.IPV6-Only支持是啥? 首先IPV6,是对IPV4地址空间的扩充.目前当我们用iOS设备连接上Wifi.4G.3G等网络时,设备被分配的地址均是IPV4地址,但是随着运营商和企业逐渐部署IP ...
 - keepalive配置支持ipv6、ipv4双棧支持
		
因公司业务需要,keepalived需要同时支持ipv6和ipv4 keepalived版本1.2.23. keepalived 配置: 重点:ipv6的虚IP配置在 virtual_ipaddres ...
 - 配置阿里云ECS支持IPv6,解决苹果app审核失败问题
		
前几天iOS的App提交给苹果审核没通过,给出的原因是:该应用在 IPv6 的环境下无法使用.检查发现:阿里云优化过的系统没有启用IPv6协议,需要配置启用一下,但是只单独启用IPv6也是无法直接提供 ...
 - 阿里云ECS centos7.2 支持IPv6
		
公司的项目因为服务器没有支持IPv6而被appstore给退回来了 第一部分 第一步:编辑 /etc/sysctl.conf 文件,将其中三条禁用IPv6的设置更改为: 第二步:使用命令启动启用IPv ...
 - 最佳实践:阿里云VPC、ECS支持IPv6啦!
		
12月6日,阿里云宣布为企业提供全栈IPv6解决方案. 阿里云专有网络VPC.云服务器ECS,作为阿里云的核心产品,也于2018年11月底上线双栈VPC.双栈ECS,目前正在对外公测中. 那么如何在阿 ...
 - nfs 支持ipv6
		
mount 一个ipv6 nfs 项目在docker里mount 一个nfs来读写,而现在需要支持ipv6,所以先写了各小demo,最后成功mount,这里记录一下 #include <sys/ ...
 
随机推荐
- Solr6.6.0 用 SimplePostTool索引文件
			
一.背景介绍 Solr启动并运行之后,并不包含任何数据,在solr的安装目录下的bin目录中,有一个post工具,我们可以使用这个工具往solr上传数据,这个工具必须在命令行中执行,post工具是一个 ...
 - 解決從Ubuntu 12.04升級至12.10之後的Unity顯示問題
			
FROM: http://blog.sina.com.cn/s/blog_97ef3ff4010190pe.html#bsh-75-306370781 今天中午經過系統自帶的“檢查更新”軟件從Ubun ...
 - Node.js 文件系统流pipe到Http响应流中
			
// 内置http模块,提供了http服务器和客户端功能(path模块也是内置模块,而mime是附加模块) var http=require("http"); var fs=req ...
 - springboot缓存及连接池配置
			
参见https://coding.imooc.com/lesson/117.html#mid=6412 1.springboot的springweb自己默认以及配置好了缓存,只需要在主文件(XxxAp ...
 - Execution failed for task ':app:transformClassesAndResourcesWithProguardForRelease'.
			
1.Execution failed for task ':app:transformClassesAndResourcesWithProguardForRelease'. 原因解析: gradle ...
 - vue-router 运行机制 及 底层原理
			
1.测试页面 index.html <!DOCTYPE html> <html lang="en"> <head> <meta chars ...
 - GMGC记实(上篇)
			
24日和25日參加了2014年GMGC大会,整体感觉今年的大会比前2届大会办的更符合听众的需求.由于今年的大会开设了开发人员训练营的分会场.在成都这样一个CP占主流的IT圈中非常有意义.另一点就是在会 ...
 - 对象序列和反序列化Xml
			
1. XmlArray和XmlArrayItem XmlArray和XmlArrayItem是不同的,XmlArray是指这个数组叫什么,XmlArrayItem 值数组的每个元素叫什么. <X ...
 - CSS遮罩层,全兼容
			
<script type="text/javascript"> $(function(){ $('#divLocker').css({ "position&q ...
 - 搭建nginx服务器和直播流媒体服务器
			
1.nginx简单说明 ① Nginx是一款轻量级的Web 服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器,并在一个BSD-like 协议下发行.其特点是占有内存少,并发能力强. ...