正向和反向获取主机和服务信息的函数,以及套接字选项设置和获取的函数原型及说明。
一、早期套接字函数原型及说明
[!NOTE]
以下仅支持解析IPv4 且 不是线程安全的
-
getsockname
功能:获取套接字本地端的地址信息原型:1
2
int getsockname(int sockfd, struct sockaddr *addr, socklen_t *addrlen);说明:
sockfd为套接字描述符,addr用于存储本地地址,addrlen传入地址结构体长度,传出实际长度。成功返回 0,失败返回 - 1(设置errno)。 -
getpeername
功能:获取套接字对端的地址信息原型:1
2
int getpeername(int sockfd, struct sockaddr *addr, socklen_t *addrlen);说明:仅适用于已连接的 TCP 套接字(
connect或accept后),参数含义同getsockname。 -
getsockopt
功能:获取套接字的选项值原型:1
2
int getsockopt(int sockfd, int level, int optname, void *optval, socklen_t *optlen);说明:
level为选项级别(如SOL_SOCKET、IPPROTO_TCP),optname为选项名,optval存储结果,optlen传入缓冲区长度并传出实际使用长度。 -
setsockopt
功能:设置套接字的选项值原型:1
2
int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen);说明:
optval为待设置的值,optlen为值的长度,其他参数同getsockopt。部分选项需在bind/connect前设置。 -
gethostbyname
功能:通过主机名获取主机信息(IPv4)原型:1
2
struct hostent *gethostbyname(const char *name);说明:已过时(仅支持 IPv4),推荐使用
getaddrinfo。返回struct hostent指针,失败返回NULL(设置h_errno)。 -
gethostbyaddr
功能:通过 IP 地址获取主机名(IPv4)原型:1
2
struct hostent *gethostbyaddr(const void *addr, socklen_t len, int type);说明:
addr为网络字节序的 IP 地址,len为地址长度(如sizeof(struct in_addr)),type为地址族(如AF_INET)。已过时。 -
getservbyname
功能:通过服务名和协议获取服务信息原型:1
2
struct servent *getservbyname(const char *name, const char *proto);说明:
name为服务名(如"http"),proto为协议(如"tcp",可为NULL)。返回struct servent指针,包含端口号(网络字节序)。 -
getservbyport
功能:通过端口号和协议获取服务信息原型:1
2
struct servent *getservbyport(int port, const char *proto);说明:
port为网络字节序的端口号(需用htons转换),其他参数同getservbyname。struct hostent(主机信息结构体)用于存储主机的相关信息(如主机名、IP 地址列表等),定义在
<netdb.h>中1
2
3
4
5
6
7struct hostent {
char *h_name; // 主机的官方名称(规范名)
char **h_aliases; // 主机的别名列表(以NULL结尾的字符串数组)
int h_addrtype; // 地址类型(如AF_INET表示IPv4,AF_INET6表示IPv6)
int h_length; // 每个地址的长度(字节),如IPv4为4,IPv6为16
char **h_addr_list; // 主机的IP地址列表(网络字节序,以NULL结尾的指针数组)
};字段说明:
-
h_name:主机的正式名称(如www.example.com)。 -
h_aliases:主机的其他别名(如example.com可能是www.example.com的别名),最后一个元素为NULL。 -
h_addrtype:地址族类型,通常为AF_INET(IPv4),但现代系统也可能支持AF_INET6(IPv6)。 -
h_length:每个 IP 地址的长度(IPv4 为 4 字节,IPv6 为 16 字节)。 -
h_addr_list:存储主机的 IP 地址数组(网络字节序),每个元素是in_addr(IPv4)或in6_addr(IPv6)结构体的指针。为方便使用,通常用宏h_addr指代h_addr_list[0](第一个 IP 地址)。
struct servent(服务信息结构体)用于存储网络服务的相关信息(如服务名、端口号、协议等),同样定义在
<netdb.h>中。1
2
3
4
5
6struct servent {
char *s_name; // 服务的官方名称(规范名)
char **s_aliases; // 服务的别名列表(以NULL结尾的字符串数组)
int s_port; // 服务对应的端口号(网络字节序)
char *s_proto; // 服务使用的协议(如"tcp"或"udp")
};字段说明:
-
s_name:服务的正式名称(如"http"、"ftp")。 -
s_aliases:服务的其他别名(如"www"可能是"http"的别名),最后一个元素为NULL。 -
s_port:服务对应的端口号,以网络字节序(大端序)存储,使用时需通过ntohs转换为主机字节序。 -
s_proto:服务使用的协议类型(如"tcp"用于面向连接的服务,"udp"用于无连接服务)。
-
二、现代套接字函数原型及说明
getaddrinfo 函数:正向解析(主机名→IP 地址,服务名→端口号)
getaddrinfo的核心功能是将主机名(或 IP 字符串) 和服务名(或端口号字符串) 转换为一组用于创建套接字的struct sockaddr结构(套接字地址结构),方便后续的bind、connect等操作。
1. 函数原型
1 |
|
2. 参数详解
| 参数名 | 类型 | 含义 |
|---|---|---|
node |
const char* |
输入参数:主机名(如"www.example.com")或 IP 地址字符串(如"192.168.1.1")。若为NULL,结合hints.ai_flags的AI_PASSIVE可用于服务器绑定通配地址(INADDR_ANY)。 |
service |
const char* |
输入参数:服务名(如"http"、"ssh")或端口号字符串(如"80"、"22")。若为NULL,则不指定端口号(需手动在返回的struct sockaddr中设置)。 |
hints |
const struct addrinfo* |
输入参数:用于过滤和指定返回结果的 “提示” 结构体。若为NULL,则默认返回所有可能的地址类型(IPv4/IPv6,TCP/UDP 等)。 |
res |
struct addrinfo** |
输出参数:指向struct addrinfo链表的指针,存储解析结果。需通过freeaddrinfo释放内存。 |
3. 关键结构体:struct addrinfo
hints和res均为struct addrinfo类型,其定义如下:
1 | struct addrinfo { |
其中核心字段说明:
-
ai_family:指定地址族,AF_INET(仅 IPv4)、AF_INET6(仅 IPv6)、AF_UNSPEC(不限制,返回所有可能)。 -
ai_socktype:指定套接字类型,SOCK_STREAM(TCP)、SOCK_DGRAM(UDP)、0(任意类型)。 -
ai_protocol:指定协议,IPPROTO_TCP(TCP)、IPPROTO_UDP(UDP)、0(任意协议)。 -
ai_flags:常用标志(可组合使用,按位或):AI_PASSIVE:用于服务器,node为NULL时,返回的地址将是通配地址(INADDR_ANYfor IPv4,in6addr_anyfor IPv6),适合bind。AI_CANONNAME:要求返回主机的规范名称(存储在ai_canonname)。AI_NUMERICHOST:node必须是 IP 地址字符串(不进行域名解析),否则返回错误。AI_NUMERICSERV:service必须是端口号字符串(不解析服务名),否则返回错误。
4. 返回值
-
成功:返回
0,res指向解析结果链表(可能有多个地址,需遍历处理)。 -
失败:返回非 0 错误码(如
EAI_NONAME表示主机名无效),可通过gai_strerror(err)获取错误信息字符串。
5. 内存释放
解析完成后,必须通过freeaddrinfo释放res指向的链表内存,避免泄漏:
1 | void freeaddrinfo(struct addrinfo *res); |
6. 使用场景
-
客户端:将服务器主机名(如
"www.baidu.com")和服务名(如"http")解析为struct sockaddr,用于connect。 -
服务器:将
NULL(主机名)和服务名(如"8080")解析为通配地址(结合AI_PASSIVE),用于bind。
getnameinfo 函数:反向解析(IP 地址→主机名,端口号→服务名)
getnameinfo是getaddrinfo的反向操作:将struct sockaddr(套接字地址结构,包含 IP 和端口)转换为主机名和服务名。
1. 函数原型
1 |
|
2. 参数详解
| 参数名 | 类型 | 含义 |
|---|---|---|
addr |
const struct sockaddr* |
输入参数:指向struct sockaddr(或sockaddr_in/sockaddr_in6)的指针,包含待解析的 IP 和端口。 |
addrlen |
socklen_t |
输入参数:addr指向的地址结构的长度(如sizeof(struct sockaddr_in))。 |
host |
char* |
输出参数:存储主机名的缓冲区(若为NULL,则不获取主机名)。 |
hostlen |
socklen_t |
输入参数:host缓冲区的大小(字节)。 |
serv |
char* |
输出参数:存储服务名的缓冲区(若为NULL,则不获取服务名)。 |
servlen |
socklen_t |
输入参数:serv缓冲区的大小(字节)。 |
flags |
int |
输入参数:控制解析行为的标志(见下文)。 |
3. 关键标志(flags)
-
NI_NAMEREQD:若无法解析主机名(如无 DNS 记录),则返回错误(EAI_NONAME),不返回 IP 字符串。 -
NI_NUMERICHOST:强制返回 IP 地址字符串(不解析为主机名)。 -
NI_NUMERICSERV:强制返回端口号字符串(不解析为服务名)。 -
NI_DGRAM:表示是 UDP 服务(默认假设是 TCP,某些服务名在 TCP 和 UDP 中可能不同)。
4. 返回值
-
成功:返回
0,host和serv缓冲区分别存储主机名和服务名(若对应参数非NULL)。 -
失败:返回非 0 错误码,可通过
gai_strerror(err)获取错误信息。
5. 使用场景
-
服务器:获取客户端连接的 IP 对应的主机名(如日志记录)。
-
网络工具:将套接字地址转换为人类可读的主机名和服务名(如
netstat显示www.baidu.com:http而非180.101.50.242:80)。
示例代码片段
1. getaddrinfo 示例(解析主机名和服务名)
1 |
|
2. getnameinfo 示例(解析 IP 地址和端口)
1 |
|