gethostname
函数获取本地主机名,然后使用
gethostbyname
解析域名,再结合
ntohs
函数从
sockaddr_in
结构体中提取端口号。
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
结构体的指针。
salen
:sockaddr
结构体的长度。
host
:用于存储获取到的主机名或IP地址的缓冲区。
hostlen
:host
缓冲区的大小。
serv
:用于存储获取到的端口号的缓冲区。
servlen
:serv
缓冲区的大小。
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; }