文章目录
一、简介
二、网络常用结构体
1、ifaddrs
struct ifaddrs {
struct ifaddrs *ifa_next; // 指向列表中下一个结构的指针。该字段在列表的最后一个结构中为 NULL
char *ifa_name; // 接口名称
unsigned int ifa_flags; // 提供有关接口的一些信息的标志
struct sockaddr *ifa_addr; // 接口地址
struct sockaddr *ifa_netmask; // 接口的网络掩码
union {
struct sockaddr *ifu_broadaddr; // 接口广播地址
struct sockaddr *ifu_dstaddr; // 点对点目的地址
} ifa_ifu;
#define ifa_broadaddr ifa_ifu.ifu_broadaddr
#define ifa_dstaddr ifa_ifu.ifu_dstaddr
void *ifa_data; // 特定地址族数据的缓冲区
};
2、sockaddr
struct sockaddr {
ushort sa_family;
char sa_data[14];
};
3、sockaddr_in
struct sockaddr_in {
short sin_family; // 网络协议
unsigned short sin_port; // 端口
struct in_addr sin_addr; // ip
char sin_zero[8];
};
struct in_addr {
unsigned long s_addr; // 使用 inet_aton() 加载
};
4、sockaddr_in6
struct sockaddr_in6 {
sa_family_t sin6_family; /* 网络协议 */
in_port_t sin6_port; /* 端口 */
uint32_t sin6_flowinfo; /* IPv6 流信息 */
struct in6_addr sin6_addr; /* ip */
uint32_t sin6_scope_id;
};
struct in6_addr {
unsigned char s6_addr[16]; /* IPv6 address */
};
三、常用函数
1、getifaddrs
#include <sys/types.h>
#include <ifaddrs.h>
int getifaddrs(struct ifaddrs **ifap);
/**
* func:函数存储对ifaddrs结构的链表的引用;
* return:成功返回0,失败返回-1;
*/
【注意】: 返回的数据是动态分配的,需要释放;
2、freeifaddrs
#include <sys/types.h>
#include <ifaddrs.h>
void freeifaddrs(struct ifaddrs *ifa);
/**
* func:释放对ifaddrs结构的链表的引用;
*/
3、getnameinfo
#include <sys/socket.h>
#include <netdb.h>
int getnameinfo(const struct sockaddr *sa, socklen_t salen,
char *host, size_t hostlen,
char *serv, size_t servlen, int flags);
/**
* func:将套接字地址转换为相应的主机和服务并返回;
* @param sa:套接字地址结构,保存输入的IP地址和端口号;
* @param salen:sa的长度;
* @param host:调用者分配缓冲区;
* @param hostlen:host长度;
* @param serv:调用者分配缓冲区;
* @param servlen:serv长度
* @param flags:
NI_NAMEREQD:若无法确定主机名,则返回一个错误;
NI_DGRAM:基于数据报(UDP)而不是基于流(TCP)的;
NI_NOFQDN:只返回本地主机的完全限定域名的主机名部分;
NI_NUMERICHOST:返回主机名的数字形式;
NI_NUMERICSERV:返回服务地址的数字形式;
* return:成功返回0,【节点和服务名称将使用以空字符结尾的字符串填充】;
失败设置errno:
EAI_AGAIN: 无法解析该名称, 稍后再试;
EAI_BADFLAGS: flags参数的值无效;
EAI_FAIL: 不可恢复的错误;
EAI_FAMILY: 无法识别地址族,或指定地址族的地址长度无效
EAI_MEMORY: 溢出;
EAI_NONAME: 名称不能解析所提供的参数
EAI_OVERFLOW: 溢出;
EAI_SYSTEM: 系统错误;
*/
【注意】:调用者可以通过提供一个NULL host(或serv)参数或一个零hostlen(或servlen)参数来指定不需要主机名(或不需要服
务名)。 但是,必须请求至少一个主机名或服务名。
四、案例
/*----------------------------------------------------------------------
> File Name: test.cpp
> Author: Jxiepc
> Mail: Jxiepc
> Created Time: Tue 22 Mar 2022 02:53:07 PM CST
----------------------------------------------------------------------*/
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netdb.h>
#include <ifaddrs.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
struct ifaddrs *ifaddr, *ifa;
int family, s;
char host[NI_MAXHOST];
if (getifaddrs(&ifaddr) == -1) {
perror("getifaddrs");
exit(EXIT_FAILURE);
}
/* 遍历链表,维护头指针,以便稍后可以释放链表 */
for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
if (ifa->ifa_addr == NULL)
continue;
family = ifa->ifa_addr->sa_family;
/* 显示接口名称和族 */
printf("%s address family: %d%s\n",
ifa->ifa_name, family,
(family == AF_PACKET) ? " (AF_PACKET)" :
(family == AF_INET) ? " (AF_INET)" :
(family == AF_INET6) ? " (AF_INET6)" : "");
/* For an AF_INET* interface address, display the address */
if (family == AF_INET || family == AF_INET6) {
s = getnameinfo(ifa->ifa_addr,
(family == AF_INET) ? sizeof(struct sockaddr_in) :
sizeof(struct sockaddr_in6),
host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
if (s != 0) {
printf("getnameinfo() failed: %s\n", gai_strerror(s));
exit(EXIT_FAILURE);
}
printf("\taddress: <%s>\n", host);
}
}
freeifaddrs(ifaddr);
exit(EXIT_SUCCESS);
}