int getaddrinfo(
const char* hostname, //主机名 or 地址串(IPv4点分十进制、IPv6十六进制数串)
const char* service, //服务名 or 十进制端口号数串
const struct addrinfo* hints, //调用者在这个结构中填入关于[期望返回]的信息类型的暗示
struct addrinfo** result //传出参数,保存getaddrinfo获得的信息,是一个链表linked-list
);
通过 hostname、service 形参,使 getaddrinfo 函数获得信息,保存到传出参数 result 中。获取的信息有哪些?详细请见 struct addrinfo 结构体介绍。
struct addrinfo{
int ai_flags; //AI_PASSIVE、AI_CANONNAME
int ai_family; //AF_XXXX:AF_INET
int ai_socktype; //SOCK_XXXX:SOCK_STREAM、SOCK_DGRAM
int ai_protocol; //0 or IPPROTO_XXXX for IPv4 and IPv6
char *ai_canonname; //主机规范名
socklen_t ai_addrlen; //length of ai_addr
struct sockaddr *ai_addr; //指向套接字地址结构
struct sockinfo *ai_next; //ptr to next structure in linked-list
}
example
#include <fcntl.h>
#include <netdb.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#define DEFAULT_ADDR "localhost"
#define DEFAULT_PORT 8120
/**
* 释放addrinfo结构体
*/
void freeaddrinfo(struct addrinfo *res)
{
free(res->ai_addr);
free(res);
}
/**
* (TCP) 发起连接<hostname/IP, port>
* @param [in] addr 主机名: 一个主机名、点分十进制地址串
* @param [in] port 服务名: 端口号
* @return 成功,返回连接套接字fd;失败,-1
* @detail
* getaddrinfo: 解决了把<主机名:服务名>转换成套接口地址结构的问题
* @example fd = cli_conn(hostname, port);
*/
int cli_conn(const char *addr, int port)
{
#define NI_MAXHOST 1025
#define NI_MAXSERV 32
char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV];
int fd, ret;
struct addrinfo hints, *res, *res0;
char port_s[6];
if (!addr) {
addr = DEFAULT_ADDR;
port = DEFAULT_PORT;
}
memset(port_s, 0, 6);
snprintf(port_s, 5, "%d", port);
memset(&hints, 0, sizeof(hints));
hints.ai_socktype = SOCK_STREAM;
ret = getaddrinfo(addr, port_s, &hints, &res0);
if (ret) {
fprintf(stderr, "unable to get address info %s, %s\n",
addr, strerror(errno));
return -1;
}
for (res = res0; res; res = res->ai_next) {
ret = getnameinfo(res->ai_addr, res->ai_addrlen, hbuf,
sizeof(hbuf), sbuf, sizeof(sbuf),
NI_NUMERICHOST | NI_NUMERICSERV);
if (ret)
continue;
fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
if (fd < 0)
continue;
reconnect:
ret = connect(fd, res->ai_addr, res->ai_addrlen);
if (ret < 0) {
if (errno == EINTR)
goto reconnect;
close(fd);
break;
}
fprintf(stderr, "connected to %s:%d\n", addr, port);
goto success;
}
fd = -1;
fprintf(stderr, "failed connect to %s:%d\n", addr, port);
success:
freeaddrinfo(res0);
return fd;
}
int main()
{
cli_conn(DEFAULT_ADDR, DEFAULT_PORT);
// sock_send();
// sock_recv();
}