本文由乌合之众 lym瞎编,欢迎转载 blog.cnblogs.net/oloroso
本文由乌合之众 lym瞎编,欢迎转载 my.oschina.net/oloroso
网络地址列表是用于保存一系列网络地址的类。它与NetAddress
无直接联系。
NetAddressList
类内部定义了一个二级指针NetAddress** fAddressArray
,在使用的时候给它动态申请一个元素个数为unsigned fNumAddresses
的指针(NetAddress*)数组
。指针数组的每一个元素又指向一个动态申请
的NetAddress
对象。
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 };
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 }
NetAddressList(char const* hostname)
构造函数很长,内容不多,但是涉及到一些网络编程的基础知识。
首先参数hostnam
e,是一个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
函数来获取它的所有地址。然后分配空间拷贝保存了这些地址。
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 }
先说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 }
这里的迭代器与之前的HanlerSet
类和DelayQueue
很像。这里NetAddressList::Iterator
在NetAddressList
类内部嵌套定义的类,权限是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 }