接口说明补充
2026/3/2大约 6 分钟
接口说明补充
getaddrinfo(3)
相关信息
network address and service translation
addrinfo
struct addrinfo {
int ai_flags;
int ai_family;
int ai_socktype;
int ai_protocol;
socklen_t ai_addrlen;
struct sockaddr *ai_addr;
char *ai_canonname;
struct addrinfo *ai_next;
};| 参数 | 值 | 用途 | 说明 |
|---|---|---|---|
| ai_flags | 0:无附加选项 AI_NUMERICHOST AI_PASSIVE AI_V4MAPED AI_ADDRCONFIG | specifies additional options | |
| ai_family | AF_INET:ipv4 AF_INET6:ipv6 AF_UNSPEC:前面两者皆可 | specifies the desired address family for the returned addresses. | |
| ai_socktype | SOCK_STREAM SOCK_DGRAM ... 0: any type | specifies the preferred socket type | |
| ai_protocol | 0: any protocol | specifies the protocol for the returned socket addresses. | |
| ai_addrlen | 0 | ||
| ai_addr | NULL | ||
| ai_canonname | NULL | If hints.ai_flags includes the AI_CANONNAME flag, then the ai_canonname field of the first of the addrinfo structures in the returned list is set to point to the official name of the host. | 规范名称 |
| next | NULL |
canon: a generally accepted rule, standard or principle by which sth is judged
getaddrinfo
int getaddrinfo(const char *restrict node,
const char *restrict service,
const struct addrinfo *restrict hints,
struct addrinfo **restrict res);| 参数 | 值 | 用途 | 说明 |
|---|---|---|---|
| node | Server: NULL Client: 192.168.56.xxx - ip地址(numerical network address) www.baidu.com - 域名(network hostname) | identify an Internet host | ip地址(主机) |
| service | http 80 | identity a service | 端口号(服务) |
| hints | NULL:any type & any protocol & AF_UNSPEC & (AI_V4MAPPED | AI_ADDRCONFIG) | points to an addrinfo structure that specifies criteria for selecting the socket address structures | |
| res | 符合条件的地址信息列表 | ||
| RETURN VALUE | 0: succeed error code |
returns one or more
addrinfostructures, each of which contains an Internet address that can be specified in a call tobind(2)orconnect(2)
对于Server, 通过getaddrinfo()可以获取可用的 ip地址,然后bind
对于client,可以方便地获取服务端的地址类型 ,然后创建对应类型的socket,再与服务端进行connect
freeaddrinfo
void freeaddrinfo(struct addrinfo *res);相关信息
The freeaddrinfo() function frees the memory that was allocated for the dynamically allocated linked list res.
示例 - client
连接到指定upd
int main(int argc, char *argv[])
{
int sfd, s;
char buf[BUF_SIZE];
size_t len;
ssize_t nread;
struct addrinfo hints;
struct addrinfo *result, *rp;
if (argc < 3) {
fprintf(stderr, "Usage: %s host port msg...\n", argv[0]);
exit(EXIT_FAILURE);
}
/* Obtain address(es) matching host/port. */
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */
hints.ai_socktype = SOCK_DGRAM; /* Datagram socket */
hints.ai_flags = 0;
hints.ai_protocol = 0; /* Any protocol */
s = getaddrinfo(argv[1], argv[2], &hints, &result);
if (s != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(s));
exit(EXIT_FAILURE);
}
/* getaddrinfo() returns a list of address structures.
Try each address until we successfully connect(2).
If socket(2) (or connect(2)) fails, we (close the socket
and) try the next address. */
for (rp = result; rp != NULL; rp = rp->ai_next) {
sfd = socket(rp->ai_family, rp->ai_socktype,
rp->ai_protocol);
if (sfd == -1)
continue;
if (connect(sfd, rp->ai_addr, rp->ai_addrlen) != -1)
break; /* Success */
close(sfd);
}
freeaddrinfo(result); /* No longer needed */
if (rp == NULL) { /* No address succeeded */
fprintf(stderr, "Could not connect\n");
exit(EXIT_FAILURE);
}
/* Send remaining command-line arguments as separate
datagrams, and read responses from server. */
for (size_t j = 3; j < argc; j++) {
len = strlen(argv[j]) + 1;
/* +1 for terminating null byte */
if (len > BUF_SIZE) {
fprintf(stderr,
"Ignoring long message in argument %zu\n", j);
continue;
}
if (write(sfd, argv[j], len) != len) {
fprintf(stderr, "partial/failed write\n");
exit(EXIT_FAILURE);
}
nread = read(sfd, buf, BUF_SIZE);
if (nread == -1) {
perror("read");
exit(EXIT_FAILURE);
}
printf("Received %zd bytes: %s\n", nread, buf);
}
exit(EXIT_SUCCESS);
}| 行号 | 功能 | 说明 |
|---|---|---|
| 17-21 | 设置服务端信息 | |
| 23 | result 指向列表首元素 | |
| 34-44 | 创建udp socket,并绑定连接 | |
| 46 | 释放 |
效果:
./Network 192.168.56.1 10086 ni hao!对端地址信息:192.168.56.1 10086
RECV ASCII/3 from 192.168.56.101 :60243 <<<
ni省去了手动填充地址结构体的步骤,并且可以通过域名指定服务端地址,同时支持IPV4 和 IPV6。
getnameinfo
address-to-name translation in protocol-independent manner
#include <sys/socket.h>
#include <netdb.h>
int getnameinfo(const struct sockaddr *sa, socklen_t salen,
char *host, socklen_t hostlen,
char *serv, socklen_t servlen, int flags);| 参数 | 值 | 用途 | 说明 |
|---|---|---|---|
| sa | a pointer to a generic socket address structure(of type sockaddr_in or sockaddr_in6) that holds the input IP address and port number | ||
| salen | sa size | ||
| host | pointer to caller-allocated buffer, null-terminated string | ||
| hostlen | host buffer size | ||
| serv | |||
| servlen | |||
| RETURAN VALUE | 0: success |
flags
| 值 | 含义 | 说明 |
|---|---|---|
| NI_NAMEREQD | If set, then an error is returned if the hostname cannot be determined. | |
| NI_DGRAM | If set, then the service is datagram (UDP) based rather than stream (TCP) based. This is required for the few ports (512-514) that have different services for UDP and TCP. | 通常同一个端口对应的TCP、UDP服务相同,但存在同一端口TCP、UDP服务不同的情况。 514,TCP:shell(远程shell); UDP: syslog(系统日志) |
| NI_NOFQDN | If set, return only the hostname part of the fully qualified domain name for local hosts. | |
| NI_NUMERICSERV | If set, then the numeric form of the service address is returned. | |
| NI_NUMERICHOST | If set, then the numeric form of the hostname is returned. |
EXAMPLE
int main(int argc, char* argv[])
{
int s;
struct addrinfo *result, *rp;
char *host = "www.baidu.com", *service = "http";
s = getaddrinfo(host, service, NULL, &result);
if (s != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(s));
exit(EXIT_FAILURE);
}
char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV];
getnameinfo(result->ai_addr, result->ai_addrlen, hbuf, sizeof(hbuf), sbuf, sizeof(sbuf), NI_NUMERICSERV);
printf("Host: %s, Service: %s\n", hbuf, sbuf);
return 0;
}字符数组长度宏定义:
#define NI_MAXHOST 1025
#define NI_MAXSERV 32效果:
Host: 36.152.44.93, Service: 80示例 - Server
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */
hints.ai_socktype = SOCK_DGRAM; /* Datagram socket */
hints.ai_flags = AI_PASSIVE; /* For wildcard IP address */
hints.ai_protocol = 0; /* Any protocol */
hints.ai_canonname = NULL;
hints.ai_addr = NULL;
hints.ai_next = NULL;
s = getaddrinfo(NULL, argv[1], &hints, &result);
if (s != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(s));
exit(EXIT_FAILURE);
}
/* getaddrinfo() returns a list of address structures.
Try each address until we successfully bind(2).
If socket(2) (or bind(2)) fails, we (close the socket
and) try the next address. */
for (rp = result; rp != NULL; rp = rp->ai_next) {
sfd = socket(rp->ai_family, rp->ai_socktype,
rp->ai_protocol);
if (sfd == -1)
continue;
if (bind(sfd, rp->ai_addr, rp->ai_addrlen) == 0)
break; /* Success */
close(sfd);
}
if (rp == NULL) { /* No address succeeded */
fprintf(stderr, "Could not bind\n");
exit(EXIT_FAILURE);
}
freeaddrinfo(result); /* No longer needed */
/* Read datagrams and echo them back to sender */
for (;;) {
peer_addr_len = sizeof(struct sockaddr_storage);
nread = recvfrom(sfd, buf, BUF_SIZE, 0,
(struct sockaddr *) &peer_addr, &peer_addr_len);
if (nread == -1)
continue; /* Ignore failed request */
char host[NI_MAXHOST], service[NI_MAXSERV];
s = getnameinfo((struct sockaddr *) &peer_addr,
peer_addr_len, host, NI_MAXHOST,
service, NI_MAXSERV, NI_NUMERICSERV);
if (s == 0)
printf("Received %zd bytes from %s:%s\n",
nread, host, service);
else
fprintf(stderr, "getnameinfo: %s\n", gai_strerror(s));
if (sendto(sfd, buf, nread, 0,
(struct sockaddr *) &peer_addr,
peer_addr_len) != nread)
fprintf(stderr, "Error sending response\n");
}sockaddr(3type)
struct sockaddr {
sa_family_t sa_family; /* Address family */
char sa_data[]; /* Socket address */
};
struct sockaddr_storage {
sa_family_t ss_family; /* Address family */
};
Internet domain sockets
#include <netinet/in.h>
struct sockaddr_in {
sa_family_t sin_family; /* AF_INET */
in_port_t sin_port; /* Port number */
struct in_addr sin_addr; /* IPv4 address */
};
struct sockaddr_in6 {
sa_family_t sin6_family; /* AF_INET6 */
in_port_t sin6_port; /* Port number */
uint32_t sin6_flowinfo; /* IPv6 flow info */
struct in6_addr sin6_addr; /* IPv6 address */
uint32_t sin6_scope_id; /* Set of interfaces for a scope */
};
struct in_addr {
in_addr_t s_addr;
};
struct in6_addr {
uint8_t s6_addr[16];
};
typedef uint32_t in_addr_t;
typedef uint16_t in_port_t;| Type | size | DESCRIPTION | 说明 |
|---|---|---|---|
| sockaddr | 16 | Describes a socket address | |
| sockaddr_storage | 128 | - at least as large as any other sockaddr * addr structures - is aligned | 可以容纳任何其他类型的地址结构体 ;内存对齐,访问更快,转换为其他类型指针时不会出问题 可以用来表示任意类型地址结构,在确定了具体类型后再转换类型 |
| sockaddr_in | 16 | Describes an IPv4 Internet domain socket address. The sin_port and sin_addr members are stored in network byte order. | 按网络字节序存储ipv4地址 |
| sockaddr_in6 | 28 | ||
| in_addr | 4 | ||
| in6_addr | 16 |
getpeername
#include <sys/socket.h>
int getpeername(int sockfd, struct sockaddr *addr, socklen_t *addrlen);get name of connected of peer socket
| 参数 | 值 | 用途 | 说明 |
|---|---|---|---|
| sockfd | 获取连接到sockfd的对端地址信息 | ||
| addr | 存储peer 地址信息 | ||
| addrlen | indicate the amount of space pointed to by addr | 如果peer地址信息长度大于addr提供的大小,那么实际信息会被截断,但是addrlen仍然为peer实际地址大小 | |
| RETURN | 0:success -1:error |
getsockname
#include <sys/socket.h>
int getsockname(int sockfd, struct sockaddr *addr, socklen_t *addrlen);get socket name
| 参数 | 值 | 用途 | 说明 |
|---|---|---|---|
| sockfd | 要获取地址的socket fd | ||
| addr | 存储地址信息 | ||
| addrlen | the actual size of the socket address | ||
| RETURN | 0: success |
inet_ntop
#include <arpa/inet.h>
const char *inet_ntop(int af, const void *src,
char *dst, socklen_t size);convert IPv4 and IPv6 addresses from binary to text form
| 参数 | 值 | 用途 | 说明 |
|---|---|---|---|
| af | AF_INET:IPv4 AF_INET6: IPv6 | address family | |
| src | network address structure | ||
| dst\output | 存储结果的字符串指针, IPv4 为ddd.ddd.ddd.ddd 格式 | ||
| size\input | INET_ADDRSTRLEN:IPv4 最小长度 INET6_ADDRSTRLEN | the number of bytes available in the buffer | |
| RETURN | NULL: error a non-null pointer to dst | 既然在参数中指定了输出结果,这里返回结果为什么不是bool类型?额,可以直接从返回值判断结果以及获取转换后的地址字符串? |