函数原型:
#include<sys/socket.h> int getsockname(int sockfd, struct sockaddr *localaddr, socklen_t *addrlen); int getpeername(int sockfd, struct sockaddr *peeraddr, socklen_t *addrlen);
函数功能:
getsockname函数用于获取与某个套接字关联的本地协议地址
getpeername函数用于获取与某个套接字关联的外地协议地址
返回值:
对于这两个函数,如果函数调用成功,则返回0,如果调用出错,则返回-1。
实例:
/*** client.c ***/ #include<stdio.h> #include<sys/socket.h> #include<netinet/in.h> #include<unistd.h> #include<string.h> #include<arpa/inet.h> #define PORT 6563 int main(int argc, char **argv) { struct sockaddr_in servaddr; struct sockaddr_in clientaddr; int sockfd; int clientaddrlen = sizeof(clientaddr); char ipAddress[INET_ADDRSTRLEN]; if (argc < 2) { printf("parameter error"); } sockfd = socket(AF_INET, SOCK_STREAM, 0); memset(&servaddr, 0 ,sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(PORT); if (inet_pton(AF_INET, argv[1], &servaddr.sin_addr) <= 0) { printf("server address error "); } connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)); getsockname(sockfd, (struct sockaddr*)&clientaddr, &clientaddrlen); printf("client:clinet address = %s:%d ",inet_ntop(AF_INET, &clientaddr.sin_addr, ipAddress, sizeof(ipAddress)), ntohs(clientaddr.sin_port)); return 0; }
/*** server.c ***/ #include<sys/socket.h> #include<stdio.h> #include<netinet/in.h> #include<unistd.h> #include<string.h> #include<arpa/inet.h> #define MAXLINE 4096 #define PORT 6563 #define LISTENQ 1024 int main() { int listenfd, connfd; struct sockaddr_in servaddr; struct sockaddr_in listenAddr, connecteAddr, peerAddr; int listenAddrlen, connectedAddrlen, perrLen; char ipAddr[INET_ADDRSTRLEN]; listenfd = socket(AF_INET, SOCK_STREAM, 0); memset(&servaddr, 0 ,sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = htonl(INADDR_ANY); servaddr.sin_port = htons(PORT); bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)); listen(listenfd, LISTENQ); listenAddrlen = sizeof(listenAddr); getsockname(listenfd,(struct sockaddr *)&listenAddr, &listenAddrlen); printf("listen address = %s:%d ",inet_ntoa(listenAddr.sin_addr), ntohs(listenAddr.sin_port)); while(1) { connfd = accept(listenfd, (struct sockaddr*)NULL, NULL); connectedAddrlen = sizeof(connecteAddr); getsockname(connfd, (struct sockaddr*)&connecteAddr, &connectedAddrlen); printf("connected server address = %s:%d ",inet_ntoa(connecteAddr.sin_addr), ntohs(connecteAddr.sin_port)); getpeername(connfd, (struct sockaddr*)&peerAddr, &perrLen); printf("connected peer address = %s:%d ",inet_ntop(AF_INET, &peerAddr.sin_addr, ipAddr, sizeof(ipAddr)), ntohs(peerAddr.sin_port)); } return 0; }
运行结果:
从上面的代码中可以看到,服务器端listenfd套接字描述符对应的地址即为绑定的通配IP地址和指定的端口,而connfd套接字描述符对应的连接的服务器端的地址为内核赋予的地址和用户指定的端口。
上面的客户端与服务器端的代码中使用了函数inet_ntoa,inet_pton对32位的地址进行转换,其中inet_ntoa是较老的函数,与它一起的还有函数inet_addr和inet_ntoa,这三个函数的定义如下:
#include<arpa/inet.h> int inet_aton(const char *strptr, struct in_addr *addrptr); in_addr_t inet_addr(const char *strptr); char *inet_ntoa(struct in_addr inaddr);
inet_aton与inet_addr函数的功能类似,都是将点分十进制的字符串表示的IP地址转换成32位的网络字节序的IPv4地址。
inet_ntoa函数将32位的网络字节序的IPv4地址转换成点分十进制的字符串表示的IP地址,inet_addr函数已被废弃,并且这三个函数只针对IPv4地址有效,在点分十进制数串和32位的网络字节序二进制值间进行转换,如果要对于IPv4和IPv6都适用,那么使用下面两个函数:
#include<arpa/inet.h> int inet_pton(int family, const char *strptr, void *addrptr); const char *inet_ntop(int family, const void *addrptr, char *strptr, size_t len);
函数中的p和n分别代表表达式(presentation)和数值(numeric)
所以inet_pton函数将strptr指针所指的字符串转换为网络地址(IPv4和IPv6),再将地址保存到addrptr指向的结构体中,inet_ntop将网络地址转为字符串表示的地址,结果存放在strptr中,len参数是strptr的大小。
这两个函数支持IPv4和IPv6,所以需要通过参数family来指定,当前要转换的是IPv4地址还是IPv6地址。