live555学习笔记之-GroupSock(NetAddress&NetAddressList&AddressPortLookupTable)

基于Live555框架实现一个实时流媒体服务(2) 在处理流媒体服务的工作中,自行编写代码不仅耗时而且容易产生错误。因此,选择一个合适的开源媒体软件框架至关重要。常见的框架有ffmpeg、GStreamer和Live555等。基于C++开发:这意味着代码不仅高效,而且具有良好的结构和可读性。代码简洁、高效:在开发流媒体服务时,这两个特点极为重要,可以减少bug的产生。通俗易懂:使得即使是初学者也能快速上手。支持深度定制:为需要特定功能的开发者提供了极大的灵活性。Live555框架的强大功能和灵活性来源于其精心设计的几个基类。 阅读详情

live/groupsock/include/NetAddress.hh

1.概述

  group是组/群的意思,socket是网络接口的代名词了。这个部分很庞大,主要是与网络相关的。而live555的网络模块很多都涉及到组播的概念。

  使用Socket进行的网络连接,网络地址一般由地址(IP)和端口(port)组成。
live555中定义了一些数据类型,表明了目前所支持的网络地址类型。

typedef u_int32_t netAddressBits;
typedef u_int16_t portNumBits;

1.1. NetAddress

  NetAddress是一个用于保存网络地址的类,它不是对struct sockaddr的封装。其内部定义了两个数据成员,分别是用于保存地址数据的u_int8_t* fData和用于指示地址长度的unsigned fLength。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CCsUspap-1595303656936)(https://note.youdao.com/yws/public/resource/b1e07c64a1c583bbabdcf3b6a8269212/xmlnote/8D5BCF80D9354016B30313208D911CA3/4710)]

class NetAddress {
public:
    //调用assign来分配空间
  NetAddress(u_int8_t const* data,
	     unsigned length = 4 /* default: 32 bits */);
  NetAddress(unsigned length = 4); // sets address data to all-zeros
  NetAddress(NetAddress const& orig);
  NetAddress& operator=(NetAddress const& rightSide);
  //析构就是对clean的调用。
  virtual ~NetAddress();
  
  unsigned length() const { return fLength; }
  u_int8_t const* data() const // always in network byte order
  { return fData; }
  
private:
  void assign(u_int8_t const* data, unsigned length);
  void clean();
  
  unsigned fLength;
  //clean方法用于将fData指向的内存空间进行释放。
  u_int8_t* fData;
};
  • assign

  先说这个而不是构造函数,是因为这个方法是一个关键方法。构造函数也要用到它。

  assign为fData成员动态分配内存空间和拷贝数据。通过参数length来确定分配空间的大小,而参数data用于作为数据源拷贝到申请的新空间。要注意的是这个方法的权限是private的,所以没有检查data==NULL也是可以的。

//为fDate申请length字节内存空间,并将data指向内容拷贝到新空间
void NetAddress::assign(u_int8_t const* data, unsigned length) {
  fData = new u_int8_t[length];
  if (fData == NULL) {
    fLength = 0;
    return;
  }

  for (unsigned i = 0; i < length; ++i)	fData[i] = data[i];
  fLength = length;
}

1.2. NetAddressList

  网络地址列表是用于保存一系列网络地址的类。它与NetAddress无直接联系。
NetAddressList类内部定义了一个二级指针NetAddress** fAddressArray,在使用的时候给它动态申请一个元素个数为unsigned fNumAddresses的指针(NetAddress*)数组。指针数组的每一个元素又指向一个动态申请的NetAddress对象。
image

class NetAddressList {
public:
    // 构造函数hostname可以是一个点分十进制的IP地址,也可以是主机域名
  NetAddressList(char const* hostname);
  NetAddressList(NetAddressList const& orig);
  NetAddressList& operator=(NetAddressList const& rightSide);
  virtual ~NetAddressList();
  //获取地址表中元素个数
  unsigned numAddresses() const { return fNumAddresses; }
  
  NetAddress const* firstAddress() const;
  
  // Used to iterate through the addresses in a list:
  // 迭代器,用于遍历列表中的地址:
  class Iterator {
  public:
    Iterator(NetAddressList const& addressList);
    NetAddress const* nextAddress(); // NULL iff none
  private:
    NetAddressList const& fAddressList;//必须绑定一个地址表
    unsigned fNextIndex;//下一个地址的索引
  };
  
private:
    //assign方法为地址表动态申请内存来保存地址元素。
  void assign(netAddressBits numAddresses, NetAddress** addressArray);
  //它的作用是将地址表和表中所有的地址元素都释放了。之前assign分配空间,在这里对应的释放。
  void clean();
  
  friend class Iterator;
  unsigned fNumAddresses;
  NetAddress** fAddressArray;
};

typedef u_int16_t portNumBits;

class Port {
public:
  Port(portNumBits num /* in host byte order */);
  
  portNumBits num() const { return fPortNum; } // in network byte order
  
private:
  portNumBits fPortNum; // stored in network byte order
#ifdef IRIX
  portNumBits filler; // hack to overcome a bug in IRIX C++ compiler
#endif
};
  • assign
void NetAddressList::assign(unsigned numAddresses, NetAddress** addressArray) {
    //为地址表分配内存空间
  fAddressArray = new NetAddress*[numAddresses];
  if (fAddressArray == NULL) {
    fNumAddresses = 0;
    return;
  }
    //为地址表每个地址分配内存空间
  for (unsigned i = 0; i < numAddresses; ++i) {
    fAddressArray[i] = new NetAddress(*addressArray[i]);
  }
  fNumAddresses = numAddresses;
}
  • NetAddressList的构造

  NetAddressList(char const* hostname)构造函数很长,内容不多,但是涉及到一些网络编程的基础知识.

  首先参数hostname,是一个C风格的字符串,如果它保存的是一个点分十进制的IP地址(例如:”192.168.1.128”),那么只会给这个地址表申请一个元素的空间来保存地址。注意,保存的地址在一个NetAddress对象中,对象里面保存的是整型数形式的地址.

  这里有一句netAddressBits addr = our_inet_addr((char*)hostname);这个函数的作用是把点分十进制的IP地址转换为整型数形式的地址。参数不是点分十进制的IP地址字符串,那么函数会返回错误码INADDR_NONE 。our_inet_addr实质上是调用的inet_addr(socket库函数),其定义在live555sourcecontrol\groupsock\inet.c文件中。

  那如果参数hostname不是一个IP地址,那么它就应该是主机名(通常指域名,如live555.com)。一个域名可能对应不止一个IP地址(windows下可以使用nslookup命令查看,linux/unix下可以用dig命令)。这里使用了gethostbyname函数来获取它的所有地址。然后分配空间拷贝保存了这些地址。

NetAddressList::NetAddressList(char const* hostname)
  : fNumAddresses(0), fAddressArray(NULL) {
  // First, check whether "hostname" is an IP address string:
  netAddressBits addr = our_inet_addr((char*)hostname);
  if (addr != INADDR_NONE) {
    // Yes, it was an IP address string.  Return a 1-element list with this address:
    //它是一个IP地址字符串,那么这个地址表只需要1个元素
    fNumAddresses = 1;
    fAddressArray = new NetAddress*[fNumAddresses];
    if (fAddressArray == NULL) return;
    //申请空间,保存这个地址。注意保存的是整数地址而不是字符串
    fAddressArray[0] = new NetAddress((u_int8_t*)&addr, sizeof (netAddressBits));
    return;
  }
    
  // "hostname" is not an IP address string; try resolving it as a real host name instead:
  // 当它不是一个IP地址字符串,尝试解析hostname真实的地址来代替
#if defined(USE_GETHOSTBYNAME) || defined(VXWORKS)
  struct hostent* host;
#if defined(VXWORKS)
  char hostentBuf[512];

  host = (struct hostent*)resolvGetHostByName((char*)hostname, (char*)&hostentBuf, sizeof hostentBuf);
#else
    //gethostbyname()返回对应于给定主机名的包含主机名字和地址信息的hostent结构指针(不要试图delete这个返回的地址)
  host = gethostbyname((char*)hostname);
#endif
  if (host == NULL || host->h_length != 4 || host->h_addr_list == NULL) return; // no luck

  u_int8_t const** const hAddrPtr = (u_int8_t const**)host->h_addr_list;
  // First, count the number of addresses:
  // First, count the number of addresses:取得地址个数
  u_int8_t const** hAddrPtr1 = hAddrPtr;
  while (*hAddrPtr1 != NULL) {
    ++fNumAddresses;
    ++hAddrPtr1;
  }

  // Next, set up the list:
  // Next, set up the list: 给地址表分配内存
  fAddressArray = new NetAddress*[fNumAddresses];
  if (fAddressArray == NULL) return;
    //逐个拷贝地址到地址表
  for (unsigned i = 0; i < fNumAddresses; ++i) {
    fAddressArray[i] = new NetAddress(hAddrPtr[i], host->h_length);
  }
#else
  // Use "getaddrinfo()" (rather than the older, deprecated "gethostbyname()"):
  struct addrinfo addrinfoHints;
  memset(&addrinfoHints, 0, sizeof addrinfoHints);
  addrinfoHints.ai_family = AF_INET; // For now, we're interested in IPv4 addresses only
  struct addrinfo* addrinfoResultPtr = NULL;
  int result = getaddrinfo(hostname, NULL, &addrinfoHints, &addrinfoResultPtr);
  if (result != 0 || addrinfoResultPtr == NULL) return; // no luck

  // First, count the number of addresses:
  const struct addrinfo* p = addrinfoResultPtr;
  while (p != NULL) {
    if (p->ai_addrlen < 4) continue; // sanity check: skip over addresses that are too small
    ++fNumAddresses;
    p = p->ai_next;
  }

  // Next, set up the list:
  fAddressArray = new NetAddress*[fNumAddresses];
  if (fAddressArray == NULL) return;

  unsigned i = 0;
  p = addrinfoResultPtr;
  while (p != NULL) {
    if (p->ai_addrlen < 4) continue;
    fAddressArray[i++] = new NetAddress((u_int8_t const*)&(((struct sockaddr_in*)p->ai_addr)->sin_addr.s_addr), 4);
    p = p->ai_next;
  }

  // Finally, free the data that we had allocated by calling "getaddrinfo()":
  freeaddrinfo(addrinfoResultPtr);
#endif
}

1.3. AddressPortLookupTable

  AddressPortLookupTable类内部定义了一个HashTable* fTable用于保存哈希表的地址。在构造函数中动态创建了一个哈希表对象给它。AddressPortLookupTable使用了两个地址和一个端口号组合作为一个key,value是Add方法的时候确定的。

  AddressPortLookupTable类只提供了增删查三种操作,没有提供修改表项的操作。
使用哈希表的优点在于可以快速的查找key对应的value。

class AddressPortLookupTable {
public:
    // 为内部哈希表fTable创建对象,哈希表的key是3个元素的unsigned int数组
  AddressPortLookupTable();
  // 释放内部哈希表fTable
  virtual ~AddressPortLookupTable();
  // 使用address1、address2、port组成key,value为值添加到哈希表 
  // 如果对应key的条目已经存在,返回旧的value,否则返回NULL
  void* Add(netAddressBits address1, netAddressBits address2, Port port, void* value);
      // Returns the old value if different, otherwise 0
    //从哈希表中移除key对应的条目,对应条目存在返回true
  Boolean Remove(netAddressBits address1, netAddressBits address2, Port port);
  // 从哈希表中查找key对应的value,没找到返回NULL
  void* Lookup(netAddressBits address1, netAddressBits address2, Port port);
      // Returns 0 if not found
  void* RemoveNext() { return fTable->RemoveNext(); }

  // Used to iterate through the entries in the table
  // 迭代器,用于遍历在表中的条目
  class Iterator {
  public:
    Iterator(AddressPortLookupTable& table);
    virtual ~Iterator();
    
    void* next(); // NULL iff none
    
  private:
    HashTable::Iterator* fIter;
  };
  
private:
  friend class Iterator;
  HashTable* fTable;
};
6 live555源码分析(六)——live555 RTSP工作流程(三) live555继承关系比较复杂,所以做图记录下h264文件发送过程中关键变量的类型。 上一篇从源码分析了OPTION和DESCRIBE的运行流程。这篇分析剩下的SETUP和PLAY的运行流程。 一、 SETUP if (!requestIncludedSessionId) { // No session id was present in the request. // So create a new "RTSPClientSession" object for this request. 阅读详情

相关推荐

live555源码分析(二)Groupsock

  Groupsock内部封装了udp套接字,用来实现组播消息群发。   Groupsock在其父类构造函数中,执行setupDatagramSocket函数初始化,创建套接字并绑定端口: Socket::Socket(UsageEnvironment& env, Port port, int family) : fEnv(DefaultUsageEnvironment != NULL ? *DefaultUsageEnvironment : env), fPort(port),

flukeshen的博客 1375

Live555源码阅读笔记(四):groupsock 目录详解

梳理这16个文件的逻辑关系和框架,根据自己的阅读经历,提供大部分函数的注释。会说到GroupsockHelper.hh、GroupsockHelper.cpp、Groupsock、NetInterface、GroupEId

wkd_007的博客 1029

android上live555获取IP为0.0.0.0的问题

live555在获取IP失败时,url中的IP地址为0.0.0.0,此时地址是不可用用的,需要解决这个问题可以修改live555的源码实现。具体可修改groupsock/GroupsockHelper.cpp 文件,在netAddressBits ourIPAddress(UsageEnvironment& env)方法中修改如下方法加入自己的获取ip方法,如本文通过修改加入了获取andro

三言两语 2888

unsigned our_inet_addr(cp) char const* cp; { return inet_addr(cp); } 的理解

老版本c中的函数参数声明方式: unsigned our_inet_addr(cp)      char const* cp; {      return inet_addr(cp); }    等价于: unsigned our_inet_addr(char const* cp) {      return inet_addr(cp); }

1252

live555学习心得二(获取本地IP地址方法1)

获取本地IP地址方法1

鹏程万里--扬帆起航 9061

【Live555】live555源码详解(三):Groupsock

6、Groupsock 组播 6.1 NetInterface NetInterface 网络接口基类,只有一个静态 public 变量 static UsageEnvironment* DefaultUsageEnvironment; // 如果非空,将用这个环境变量创建socket 6.2 Socket Socket 继承自 NetInterface,主要功能:创建、配置socket 主要接口: reset :关闭socket,并将描述符 fSocketNum 设置为 -1 socketNum :

郭老二 1345

live555 groupsock

live555 groupsock groupsock的继承关系 class destRecord { public: destRecord(struct in_addr const& addr, Port const& port, u_int8_t ttl, unsigned sessionId, destRecord* next); virtual ~destRecord(); public: destRecord* fNext; GroupEId fGr

dongkun152的专栏 442

深入理解Live555多媒体库的类层次结构

Live555是一个开源的跨平台C++媒体流服务器库,它提供了一套完整的实时流传输协议(RTSP)、实时传输协议(RTP)和实时控制协议(RTCP)的实现。它支持多种媒体格式,并在多媒体直播、点播和音视频通信等领域有着广泛应用。实时流协议(RTSP)是一种网络控制协议,它被设计用来控制流媒体服务器。RTSP提供了一个可扩展框架,使客户端能够控制流媒体会话,如暂停、播放、快进和倒退。它允许客户端发送会话控制命令,而服务器响应这些请求并返回会话状态。

weixin_35749545的博客 493

LIVE555研究之三:LIVE555基础

LIVE555基础      LIVE555是为流媒体提供解决方案的跨平台C++开源项目。从今天起我们将正式开始深入LIVE555代码。 一、各库简要介绍     LIVE555下包含LiveMedia、UsageEnvironment、BasicUsageEnvironment、GroupSock库,MediaServer简单服务器程序以及其他多个测试demo。     LiveMedia库:包

ithzhang 1万+

SCS 43. 利用Scissor算法从单细胞数据中挖掘临床表型关联的细胞亚群

本文详细介绍了Scissor算法在单细胞转录组数据分析中的应用,该算法能够精准挖掘与临床表型关联的细胞亚群。通过建立单细胞RNA测序数据与临床预测模型的直接关联,Scissor避免了传统聚类方法的局限性,为疾病机制研究和个性化医疗提供了新工具。文章还涵盖了数据预处理、模型选择、结果验证等实战技巧。

weixin_28736335的博客 492

聊一聊固态电池和钠离子电池新技术

总之,固态电池是一种“安全又高效的未来电池”,它的好处非常明显,但目前还处于研发阶段,离普及还有一段距离。未来,这两种技术可能会与锂离子电池并存,分别满足不同的市场需求。我尝试用最通俗易懂的语言将复杂的技术讲给大家听。钠离子电池和锂离子电池的工作原理很相似,但它用的是。固态电池和钠离子电池是两种正在研发和推广的。,它们有潜力解决现有锂离子电池的部分缺点。,而不是锂(Li)。

weixin_33324696的博客 3333

live555学习笔记2

二 基础类 讲几个重要的基础类: BasicUsageEnvironment和UsageEnvironment中的类都是用于整个系统的基础功能类.比如UsageEnvironment代表了整个系统运行的环境,它提供了错误记录和错误报告的功能,无论哪一个类要输出错误,就需要保存UsageEnvironment的指针.而TaskScheduler则提供了任务调度功能.整个程序的运行发动机就是它,它...

wodamazi 261

STM32F4三重ADC+DMA双缓冲实战:用CubeMX搞定同步采样,告别数据覆盖烦恼

本文详细介绍了STM32F4三重ADC与DMA双缓冲技术的实战应用,通过CubeMX配置实现同步采样,解决数据覆盖问题。内容涵盖硬件架构解析、CubeMX工程配置、双缓冲实现技巧及调试优化方法,适用于电机控制、电力监测等需要高精度多通道信号采集的场景。

weixin_30627341的博客 357

live555如何判断一个IP地址是否为组播地址的

介绍了live555如何判断一个IPv4地址是否为组播的方法。

纵横千里 捭阖四方 的专栏 5064

详解卷积神经网络(CNN)

卷积神经网络(Convolutional Neural Network, CNN)是一种前馈神经网络,它的人工神经元可以响应一部分覆盖范围内的周围单元,对于大型图像处理有出色表现。

qq_25762497的博客 25万+

[RK3588从入门到精通] 专栏目录及介绍

[RK3588从入门到精通] 专栏目录及介绍

nb124667390的博客 6498

live555 建立RTP会话

建立RTP会话

yuanchunsi的博客 782

ChatGPT Plus账号被降智?3个实用检测方法+终极解决方案(附国内支付指南)

本文针对ChatGPT Plus账号性能下降问题,提供了3个科学检测方法和系统级解决方案。通过详细分析症状、专业诊断技巧和优化策略,帮助用户有效应对GPT-4o等高级功能失效、响应质量下降等问题,特别包含国内用户关心的支付方案和账号管理建议。

weixin_42639633的博客 472

live555调试:无法确定源地址问题

在一台新的linux电脑上编译运行live555,出现错误:Unable to determine our source address: This computer has an invalid IP address: 0.0.0.0 的问题,出现这个问题多半是系统防火墙的问题,网上有解决方法是在/etc/sysconfig/iptables 添加:-A INPUT -m state...

Biao 3528

【异常】OpenClaw 项目 `fetch failed` 报错问题排查与解决方案Response interrupted: TypeError: fetch failed

针对无超时控制、异常兜底缺失导致的请求中断,封装标准化的安全请求工具,一次性解决超时控制、异常捕获、日志埋点三大问题,全项目替换原生。:将项目运行的 Node.js 版本升级至 18.x 及以上 LTS 版本,使用 Node.js 内置的稳定版。实现的网络请求环节,包括但不限于:第三方开放接口调用、内部服务接口通信、跨域资源请求、外部配置拉取等场景。:针对无法升级 Node.js 版本的存量环境,通过社区稳定兼容包替换原生。类型异常,直接造成业务请求响应中断。第二步:业务代码改造,替换原生。

奶爸的编程之路,也就一周冷个三天 367

【网络基础2】路由器的 “两扇门”:二层接口和三层接口到底有啥不一样?

家里的路由器背后总有几个网线接口,有的标着 “LAN”,有的标着 “WAN”;公司机房的路由器上,接口更是五花八门,有的插着网线,有的连着光纤,旁边还贴着 “GE0/0/1”“Eth-Trunk1” 这样的标签。你可能会想:不就是插网线的地方吗?有啥区别?其实,这些接口分 “二层接口” 和 “三层接口”,它们的作用差得远了 —— 就像你家的门,有的是 “小区内的单元门”(只通小区内部),有的是 “小区的大门”(能通往外面的世界)。接下来,咱们用大白话 + 生活例子,一点点把这两种接口讲透。

jundao1997的专栏 565

去除防火墙和虚拟机对live555启动IP地址的影响

live555 使用配置文件来获取IP地址,启动时使用

qianbo042311的博客 482

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

如何在VLC中支持IPv6 RTSP流媒体播放

前段时间遇到一个项目,要求在IPv6的网络环境中实现RTSP流媒体播放,支持点播和直播。然而,RTSP 1.0协议,RFC2326中并未定义如何支持IPv6,因此很多人认为在IPv6网络环境中无法实现RTSP 1.0的流媒体播放,而RTSP 2.0目前还处于草案状态,并未最终通过

1万+

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

Java网络编程学习

java网络编程的学习笔记

weixin_64026220的博客 318

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

live555 推RTSP音视频流总结(二) 修改RTSP Server 推流URL地址

jjjjjjjjj

weixin_39369053的博客 3135
上一篇: live555四大基础组件学习笔记-处理程序handler类
下一篇: C++中虚函数的作用和虚函数的工作原理
BERLIN23
博客等级 码龄14年 7粉丝 16原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值