Linux 编程 之 【socket】 getaddrinfo

来源:互联网 发布:一对一视频聊天软件 编辑:程序博客网 时间:2024/06/07 16:42

【说明】
  包含头文件:
  #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
0 0
原创粉丝点击