int getpeername(int s, struct sockaddr *name, socklen_t *namelen);
描述
獲取socket的對方地址
struct sockaddr_in sa;
int len = sizeof(sa);
if(!getpeername(sockfd, (struct sockaddr *)&sa, &len))
{
printf( "對方IP:%s ", inet_ntoa(sa.sin_addr));
printf( "對方PORT:%d ", ntohs(sa.sin_port));
}
補充:getsockname和getpeername調度時機很重要,如果調用時機不對,則無法正確獲得地址和端口。
TCP
對於服務器來說,在bind以后就可以調用getsockname來獲取本地地址和端口,雖然這沒有什么太多的意義。getpeername只有在鏈接建立以后才調用,否則不能正確獲得對方地址和端口,所以他的參數描述字一般是鏈接描述字而非監聽套接口描述字。
對於客戶端來說,在調用socket時候內核還不會分配IP和端口,此時調用getsockname不會獲得正確的端口和地址(當然鏈接沒建立更不可能調用getpeername),當然如果調用了bind 以后可以使用getsockname。想要正確的到對方地址(一般客戶端不需要這個功能),則必須在鏈接建立以后,同樣鏈接建立以后,此時客戶端地址和端口就已經被指定,此時是調用getpeername的時機。
UDP
UDP分為鏈接和沒有鏈接2種(這個到UDP與connect可以找到相關內容)
沒有鏈接的UDP不能調用getpeername,但是可以調用getsockname,和TCP一樣,他的地址和端口不是在調用socket就指定了,而是在第一次調用sendto函數以后
已經鏈接的UDP,在調用connect以后,這2個函數都是可以用的(同樣,getpeername也沒太大意義。如果你不知道對方的地址和端口,不可能會調用connect)。
//獲取fd對應的ip和port
static void get_peer_ip_port(int fd, char **ip, int *port)
{
int client_fd = fd;
// discovery client information
struct sockaddr_in addr;
socklen_t addrlen = sizeof(addr);
if(getpeername(client_fd, (struct sockaddr*)&addr, &addrlen) == -1){
fprintf(stderr,"discovery client information failed, fd=%d, errno=%d(%#x).\n", client_fd, errno, errno);
return;
}
// ip v4 or v6
char *buf = malloc(INET6_ADDRSTRLEN);
memset(buf, 0, INET6_ADDRSTRLEN);
if((inet_ntop(addr.sin_family, &addr.sin_addr, buf, INET6_ADDRSTRLEN)) == NULL){
fprintf(stderr,"convert client information failed, fd=%d, errno=%d(%#x).\n", client_fd, errno, errno);
return;
}
*port = ntohs(addr.sin_port);
fprintf(stdout, "get peer ip of client ip=%s, port=%d, fd=%d\n", buf, *port, client_fd);
*ip = buf;
return;
}