【说明】
包含头文件:
#include<netdb.h>
函数原型:
int getaddrinfo( const char *hostname, const char *service, const struct addrinfo *hints, struct addrinfo **res );
参数说明:
hostname 一个主机名或者地址串(IPv4的点分十进制串或者IPv6的16进制串)
service 服务,即端口号,可以是一个服务的名称,比如"http", 也可以是一个数字字符串,比如“80”
hints 可以理解为约束条件,即你创建的,要获得的addrinfo结构,有什么约束,在hints中进行设置
res 这个就是我们最终获得的addrinfo结构
功能说明:
getaddrinfo 提供了将主机名和服务名转换成套接口地址结构(网络序)的功能
产生原因:
之前套接字编程,要得到sockaddr类型: 必须使用两种函数 getserverbyname(一类的函数 和 gethostent (一类的函数), 然后构建 sockaddr_in 结构,再强制类型转换得到 sockaddr结构。 而有了getaddrinfo这个函数后,直接调用就能得到sockaddr。
使用说明:
如果本函数返回成功,那么由res参数指向的变量已被填入一个指针,它指向的是由其中的ai_next成员串联起来的addrinfo结构链表。可以导致返回多个addrinfo结构的情形有以下两个:
1)如果与hostname参数关联的地址有多个,那么适用于所请求地址簇的每个地址都返回一个对应的结构。
当hints.ai_socktype=0,即未指定socket类型,则能会返回SOCK_DGRAM、SOCK_STREAM、SOCK_SEQPACKET等多种类型的addrinfo结构;
当指定hints.ai_socktype为SOCK_DGRAM或SOCK_STREAM时,则只会返回指定类型的addrinfo结构
例如,下面实例中hints.ai_socktype=SOCK_DGRAM,因此,for循环只能看到SOCK_DGRAM类型的addrinfo被获取。
2)如果service参数指定的服务支持多个套接口类型,那么每个套接口类型都可能返回一个对应的结构,具体取决于hints结构的ai_socktype成员。
参考:
http://www.cnblogs.com/chinacloud/archive/2011/08/11/2135141.html
http://www.cnblogs.com/lovell/archive/2010/09/19/1831233.html
server端代码与上篇相同
【代码示例 client】
/* udp client */
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include <netdb.h>
#define SERVER_PORT 8888
#define LOCAL_PORT 0
#define BUFLEN 512
int main(int argc, char** argv)
{
int sockfd, rec_len, addrlen = sizeof(struct sockaddr);
char recvbuf[BUFLEN] = {0}, sendbuf[BUFLEN] = {0};
struct sockaddr_in localaddr, rcvaddr, *psockin = NULL;
struct addrinfo hints, *res = NULL, *pAddrInfo = NULL;
const char *addr;
char buf[INET_ADDRSTRLEN];
//server address
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_DGRAM;
hints.ai_protocol = 0;
hints.ai_flags = 0;
if(0 != getaddrinfo("127.0.0.1", "8888", &hints, &res))
{
printf("getaddriinfo error \r\n");
exit(1);
}
for (pAddrInfo = res; pAddrInfo != NULL; pAddrInfo = pAddrInfo->ai_next)
{
psockin = (struct sockaddr_in *)pAddrInfo->ai_addr;
addr = inet_ntop(AF_INET, &psockin->sin_addr, buf, INET_ADDRSTRLEN);
printf("### addrinfo[%d-%d-%d] addr = %s port = %d ###\r\n",
pAddrInfo->ai_family, pAddrInfo->ai_socktype, pAddrInfo->ai_protocol,
addr?addr:"unknow", ntohs(psockin->sin_port));
}
if( (sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) < 0){
printf("Client create socket error(%d): %s \r\n", errno, strerror(errno));
exit(1);
}
//local address
memset(&localaddr, 0, sizeof(localaddr));
localaddr.sin_family = AF_INET;
localaddr.sin_addr.s_addr = htonl(INADDR_ANY); //内核分配IP
localaddr.sin_port = htons(LOCAL_PORT); //内核分配端口,且不会冲突
if( bind(sockfd, (struct sockaddr*)&localaddr, sizeof(localaddr)) < 0){
perror("Client bind");
exit(1);
}
//main loop
while(1)
{
printf("----- Client send to server: ----%d-%d-%d-%d-%x-%d-%d\n", SOCK_DGRAM, res->ai_family, res->ai_socktype, res->ai_protocol,
((struct sockaddr_in*)(res->ai_addr))->sin_addr.s_addr, ((struct sockaddr_in*)(res->ai_addr))->sin_port, res->ai_addrlen);
fgets(sendbuf, BUFLEN, stdin);
if( sendto(sockfd, sendbuf, strlen(sendbuf), 0, res->ai_addr,res->ai_addrlen) < 0)
{
perror("Client sendto");
exit(1);
}
if((rec_len = recvfrom(sockfd, recvbuf, BUFLEN, 0,(struct sockaddr *)&rcvaddr, &addrlen)) == -1) {
perror("Client recvfrom");
exit(1);
}
if((((struct sockaddr_in*)(res->ai_addr))->sin_addr.s_addr != rcvaddr.sin_addr.s_addr)
|| (((struct sockaddr_in*)(res->ai_addr))->sin_port != rcvaddr.sin_port))
{
printf("Client received data, but srcAddr isn't the server. \r\n");
memset(recvbuf, 0, sizeof(recvbuf));
continue;
}
recvbuf[rec_len] = '\0';
printf("Client received: %s From ip=%d port=%d \r\n", recvbuf, ntohl(rcvaddr.sin_addr.s_addr), ntohs(rcvaddr.sin_port));
memset(recvbuf, 0, BUFLEN);<span style="font-family: Arial, Helvetica, sans-serif;"></span>
sleep(10);
}
close(sockfd);
exit(0);
} 【执行】root@linux-virtual-machine:/home/linux/01_Code/temp# ./udp-server &
[1] 3105
root@linux-virtual-machine:/home/linux/01_Code/temp#
======Server waiting for client's packets======
root@linux-virtual-machine:/home/linux/01_Code/temp# ./udp-client2
### addrinfo[2-2-17] addr = 127.0.0.1 port = 8888 ### /* 通过getaddrinfo函数获取的addrinfo信息 */
----- Client send to server: ----2-2-2-17-100007f-47138-16
fafafawegeatreatr
Server receive from client: fafafawegeatreatr
From ip=2130706433 port=54241
Client received: Hi,server has received packets!
From ip=2130706433 port=8888
----- Client send to server: ----2-2-2-17-100007f-47138-16
^C
本文详细介绍了Linux编程中用于网络连接的getaddrinfo函数,包括其功能、参数说明以及使用场景。getaddrinfo将主机名和服务名转换为套接字地址结构,简化了之前的套接字编程步骤。文中提供了client端代码示例,展示了如何利用getaddrinfo获取并使用地址信息进行UDP通信。

1292

被折叠的 条评论
为什么被折叠?



