29 GroupSock(NetAddressList)——live555源码阅读(四)网络

29 GroupSock(NetAddressList)——live555源码阅读(四)网络

本文由乌合之众 lym瞎编,欢迎转载 blog.cnblogs.net/oloroso
本文由乌合之众 lym瞎编,欢迎转载 my.oschina.net/oloroso

简介

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

NetAddressList的定义

 1 class NetAddressList {
 2 public:
 3     // 构造函数hostname可以是一个点分十进制的IP地址,也可以是主机域名
 4     NetAddressList(char const* hostname);
 5     NetAddressList(NetAddressList const& orig);
 6     NetAddressList& operator=(NetAddressList const& rightSide);
 7     virtual ~NetAddressList();
 8     //获取地址表中元素个数
 9     unsigned numAddresses() const { return fNumAddresses; }
10     //获取地址表第一个地址的内存地址
11     NetAddress const* firstAddress() const;
12 
13     // Used to iterate through the addresses in a list:
14     // 用于遍历列表中的地址:
15     class Iterator {
16     public:
17         Iterator(NetAddressList const& addressList);
18         NetAddress const* nextAddress(); // NULL iff none没有跟多地址了
19     private:
20         NetAddressList const& fAddressList; //必须绑定一个地址表
21         unsigned fNextIndex;    //下一个地址的索引
22     };
23 
24 private:
25     //为地址表申请内存空间,并将表addressArray中的内容拷贝进去
26     void assign(netAddressBits numAddresses, NetAddress** addressArray);
27     //删除地址表和地址表中所有地址
28     void clean();
29 
30     friend class Iterator;
31     unsigned fNumAddresses;     //地址个数
32     NetAddress** fAddressArray; //地址表
33 };
NetAddressList 定义

assign方法

assign方法为地址表动态申请内存来保存地址元素。
要注意的是,这里所有的地址元素都是动态申请来的,所以释放的时候不知只释放fAddressArray指向的内存空间。

 1 void NetAddressList::assign(unsigned numAddresses, NetAddress** addressArray) {
 2     //为地址表分配内存空间
 3     fAddressArray = new NetAddress*[numAddresses];
 4     if (fAddressArray == NULL) {
 5         fNumAddresses = 0;
 6         return;
 7     }
 8     //为地址表每个地址分配内存空间
 9     for (unsigned i = 0; i < numAddresses; ++i) {
10         fAddressArray[i] = new NetAddress(*addressArray[i]);
11     }
12     fNumAddresses = numAddresses;
13 }
assign 方法

NetAddressList的构造

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

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

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

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

 1 NetAddressList::NetAddressList(char const* hostname)
 2 : fNumAddresses(0), fAddressArray(NULL) {
 3     // First, check whether "hostname" is an IP address string:
 4     // 首先,检查“hostname”是否是一个IP地址字符串
 5     netAddressBits addr = our_inet_addr((char*)hostname);
 6     if (addr != INADDR_NONE) {
 7         // Yes, it was an IP address string.  Return a 1-element list with this address:
 8         //它是一个IP地址字符串,那么这个地址表只需要1个元素
 9         fNumAddresses = 1;
10         fAddressArray = new NetAddress*[fNumAddresses];
11         if (fAddressArray == NULL) return;
12         //申请空间,保存这个地址。注意保存的是整数地址而不是字符串
13         fAddressArray[0] = new NetAddress((u_int8_t*)&addr, sizeof (netAddressBits));
14         return;
15     }
16 
17     // "hostname" is not an IP address string; try resolving it as a real host name instead:
18     // 当它不是一个IP地址字符串,尝试解析hostname真实的地址来代替
19 #if defined(USE_GETHOSTBYNAME) || defined(VXWORKS)
20     struct hostent* host;
21 #if defined(VXWORKS)
22     char hostentBuf[512];
23 
24     host = (struct hostent*)resolvGetHostByName((char*)hostname, (char*)&hostentBuf, sizeof hostentBuf);
25 #else
26     //gethostbyname()返回对应于给定主机名的包含主机名字和地址信息的hostent结构指针(不要试图delete这个返回的地址)
27     host = gethostbyname((char*)hostname);
28 #endif
29     if (host == NULL || host->h_length != 4 || host->h_addr_list == NULL) return; // no luck      //不幸,没有得到
30 
31     u_int8_t const** const hAddrPtr = (u_int8_t const**)host->h_addr_list;
32     // First, count the number of addresses:取得地址个数
33     u_int8_t const** hAddrPtr1 = hAddrPtr;
34     while (*hAddrPtr1 != NULL) {
35         ++fNumAddresses;
36         ++hAddrPtr1;
37     }
38 
39     // Next, set up the list: 给地址表分配内存
40     fAddressArray = new NetAddress*[fNumAddresses];
41     if (fAddressArray == NULL) return;
42     //逐个拷贝地址到地址表
43     for (unsigned i = 0; i < fNumAddresses; ++i) {
44         fAddressArray[i] = new NetAddress(hAddrPtr[i], host->h_length);
45     }
46 #else
47     // Use "getaddrinfo()" (rather than the older, deprecated "gethostbyname()"):
48     struct addrinfo addrinfoHints;
49     memset(&addrinfoHints, 0, sizeof addrinfoHints);
50     addrinfoHints.ai_family = AF_INET; // For now, we're interested in IPv4 addresses only
51     struct addrinfo* addrinfoResultPtr = NULL;
52     int result = getaddrinfo(hostname, NULL, &addrinfoHints, &addrinfoResultPtr);
53     if (result != 0 || addrinfoResultPtr == NULL) return; // no luck
54 
55     // First, count the number of addresses:
56     const struct addrinfo* p = addrinfoResultPtr;
57     while (p != NULL) {
58         if (p->ai_addrlen < 4) continue; // sanity check: skip over addresses that are too small
59         ++fNumAddresses;
60         p = p->ai_next;
61     }
62 
63     // Next, set up the list:
64     fAddressArray = new NetAddress*[fNumAddresses];
65     if (fAddressArray == NULL) return;
66 
67     unsigned i = 0;
68     p = addrinfoResultPtr;
69     while (p != NULL) {
70         if (p->ai_addrlen < 4) continue;
71         fAddressArray[i++] = new NetAddress((u_int8_t const*)&(((struct sockaddr_in*)p->ai_addr)->sin_addr.s_addr), 4);
72         p = p->ai_next;
73     }
74 
75     // Finally, free the data that we had allocated by calling "getaddrinfo()":
76     freeaddrinfo(addrinfoResultPtr);
77 #endif
78 }
NetAddressList 构造函数

clean方法与析构

先说clean方法,它的作用是将地址表和表中所有的地址元素都释放了。之前assign分配空间,在这里对应的释放。

1 void NetAddressList::clean() {
2     while (fNumAddresses-- > 0) {   //逐个删除地址
3         delete fAddressArray[fNumAddresses];
4     }   
5     //释放地址表
6     delete[] fAddressArray; fAddressArray = NULL;
7 }

析构函数就是简单的调用clean

1 NetAddressList::~NetAddressList() {
2     clean();
3 }

拷贝构造与赋值运算符重载

这里就不多说了,代码很明白。(有人问赋值和拷贝构造的区别,这里简单说一下。拷贝构造的重点在于构造,是对象还没有的时候调用来创建一个一样的对象的,而赋值的重点在于赋值,是对象已经存在的时候,用来替换对象数据的。)

 1 NetAddressList::NetAddressList(NetAddressList const& orig) {
 2     assign(orig.numAddresses(), orig.fAddressArray);
 3 }
 4 
 5 NetAddressList& NetAddressList::operator=(NetAddressList const& rightSide) {
 6     if (&rightSide != this) {
 7         clean();
 8         assign(rightSide.numAddresses(), rightSide.fAddressArray);
 9     }
10     return *this;
11 }

NetAddressList::Iterator迭代器

这里的迭代器与之前的HanlerSet类和DelayQueue很像。这里NetAddressList::IteratorNetAddressList类内部嵌套定义的类,权限是public。在构造的时候,其也需要绑定一个NetAddressList对象,迭代器方法nextAddress返回类型是NetAddress const*,这里要注意一下。

1 NetAddressList::Iterator::Iterator(NetAddressList const& addressList)
2 : fAddressList(addressList), fNextIndex(0) {}
3 
4 NetAddress const* NetAddressList::Iterator::nextAddress() {
5     if (fNextIndex >= fAddressList.numAddresses()) return NULL; // no more
6     return fAddressList.fAddressArray[fNextIndex++];
7 }
原文地址:https://www.cnblogs.com/oloroso/p/4613361.html