当前位置:首页 > 行业动态 > 正文

如何获取域名和端口信息?——域名端口查询指南

问题:,c 获取域名和端口 回答:,在C语言中,可以使用 gethostname函数获取本地主机名,然后使用 gethostbyname解析域名,再结合 ntohs函数从 sockaddr_in结构体中提取端口号。

使用`getaddrinfo`函数

1、函数介绍getaddrinfo是POSIX标准的一部分,它提供了一种独立于协议的方式来解析主机名和服务名,支持IPv4和IPv6,线程安全且能提供更详细的错误信息。

2、函数原型

#include <sys/types.h>

#include <sys/socket.h>

#include <netdb.h>

int getaddrinfo(const char node, const char service, const struct addrinfo hints, struct addrinfo res);

3、参数说明

node:要解析的主机名或IP地址字符串。

service:服务名或端口号字符串,如果为NULL,则不指定端口号。

hints:一个可选的addrinfo结构体,用于提供输入数据,如地址族、套接字类型等。

res:一个指向addrinfo结构体链表的指针,用于输出结果。

4、示例代码

   #include <stdio.h>
   #include <stdlib.h>
   #include <string.h>
   #include <sys/types.h>
   #include <sys/socket.h>
   #include <netdb.h>
   #include <arpa/inet.h>
   int main() {
       struct addrinfo hints, res;
       int status;
       char ipstr[INET6_ADDRSTRLEN];
       memset(&hints, 0, sizeof(hints));
       hints.ai_family = AF_UNSPEC; // 允许IPv4或IPv6
       hints.ai_socktype = SOCK_STREAM; // TCP流
       status = getaddrinfo("www.example.com", NULL, &hints, &res);
       if (status != 0) {
           fprintf(stderr, "getaddrinfo error: %s
", gai_strerror(status));
           exit(EXIT_FAILURE);
       }
       for (struct addrinfo p = res; p != NULL; p = p->ai_next) {
           void addr;
           char ipver;
           if (p->ai_family == AF_INET) { // IPv4
               struct sockaddr_in ipv4 = (struct sockaddr_in )p->ai_addr;
               addr = &(ipv4->sin_addr);
               ipver = "IPv4";
           } else { // IPv6
               struct sockaddr_in6 ipv6 = (struct sockaddr_in6 )p->ai_addr;
               addr = &(ipv6->sin6_addr);
               ipver = "IPv6";
           }
           inet_ntop(p->ai_family, addr, ipstr, sizeof(ipstr));
           printf("%s: %s
", ipver, ipstr);
       }
       freeaddrinfo(res);
       return 0;
   }

使用getnameinfo函数(适用于已建立连接的套接字)

如何获取域名和端口信息?——域名端口查询指南

1、函数介绍getnameinfo函数可以从已建立连接的套接字中获取对端主机的IP地址和端口号等信息。

2、函数原型

#include <sys/types.h>

#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);

3、参数说明

sa:指向存储了远程地址信息的sockaddr结构体的指针。

salensockaddr结构体的长度。

如何获取域名和端口信息?——域名端口查询指南

host:用于存储获取到的主机名或IP地址的缓冲区。

hostlenhost缓冲区的大小。

serv:用于存储获取到的端口号的缓冲区。

servlenserv缓冲区的大小。

flags:用于指定返回值的标志,通常设置为NI_NUMERICHOST|NI_NUMERICSERV以获取数值形式的IP地址和端口号。

4、示例代码

   #include <stdio.h>
   #include <stdlib.h>
   #include <string.h>
   #include <sys/types.h>
   #include <sys/socket.h>
   #include <netdb.h>
   #include <unistd.h>
   #include <arpa/inet.h>
   int main() {
       int sockfd;
       struct sockaddr_in addr;
       char host[NI_MAXHOST];
       char service[NI_MAXSERV];
       // 创建一个套接字
       sockfd = socket(AF_INET, SOCK_STREAM, 0);
       if (sockfd < 0) {
           perror("socket");
           exit(EXIT_FAILURE);
       }
       // 设置服务器地址和端口号
       memset(&addr, 0, sizeof(addr));
       addr.sin_family = AF_INET;
       addr.sin_port = htons(80); // 例如HTTP服务的端口号80
       inet_pton(AF_INET, "www.example.com", &addr.sin_addr);
       // 连接到服务器
       if (connect(sockfd, (struct sockaddr )&addr, sizeof(addr)) < 0) {
           perror("connect");
           close(sockfd);
           exit(EXIT_FAILURE);
       }
       // 获取对端主机的IP地址和端口号
       if (getnameinfo((struct sockaddr )&addr, sizeof(addr), host, NI_MAXHOST, service, NI_MAXSERV, NI_NUMERICHOST | NI_NUMERICSERV) != 0) {
           perror("getnameinfo");
           close(sockfd);
           exit(EXIT_FAILURE);
       }
       printf("Host: %s, Service: %s
", host, service);
       // 关闭套接字
       close(sockfd);
       return 0;
   }

使用getsockname函数(适用于已绑定的套接字)

1、函数介绍getsockname函数可以获取本地已绑定套接字的IP地址和端口号。

2、函数原型

如何获取域名和端口信息?——域名端口查询指南

#include <sys/types.h>

#include <sys/socket.h>

int getsockname(int sockfd, struct sockaddr addr, socklen_t addrlen);

3、参数说明

sockfd:套接字描述符。

addr:指向sockaddr结构体的指针,用于存储获取到的本地地址信息。

addrlen:指向socklen_t类型的变量的指针,用于存储addr结构体的长度。

4、示例代码

   #include <stdio.h>
   #include <stdlib.h>
   #include <string.h>
   #include <sys/types.h>
   #include <sys/socket.h>
   #include <netinet/in.h>
   #include <arpa/inet.h>
   #include <unistd.h>
   int main() {
       int sockfd;
       struct sockaddr_in addr;
       socklen_t addrlen = sizeof(addr);
       char ipstr[INET_ADDRSTRLEN];
       // 创建一个套接字并绑定到本地端口
       sockfd = socket(AF_INET, SOCK_STREAM, 0);
       if (sockfd < 0) {
           perror("socket");
           exit(EXIT_FAILURE);
       }
       memset(&addr, 0, sizeof(addr));
       addr.sin_family = AF_INET;
       addr.sin_port = htons(8080); // 本地端口号8080
       addr.sin_addr.s_addr = htonl(INADDR_ANY); // 绑定到所有本地地址
       if (bind(sockfd, (struct sockaddr )&addr, sizeof(addr)) < 0) {
           perror("bind");
           close(sockfd);
           exit(EXIT_FAILURE);
       }
       // 获取本地套接字的IP地址和端口号
       if (getsockname(sockfd, (struct sockaddr )&addr, &addrlen) != 0) {
           perror("getsockname");
           close(sockfd);
           exit(EXIT_FAILURE);
       }
       inet_ntop(AF_INET, &(addr.sin_addr), ipstr, sizeof(ipstr));
       printf("Local IP: %s, Port: %d
", ipstr, ntohs(addr.sin_port));
       // 关闭套接字
       close(sockfd);
       return 0;
   }