C/C++ socket編程(1)
1.主機名到IP地址的映射。
IPv4中使用gethostbyname()函數完成主機名到地址解析,這個函數僅僅支持IPv4,且不允許調用者指定所需地址類型的任何信息,返回的結構只包含了用於存儲IPv4地址的空間。例子:
bool MY_getHostbyName(char * const hostname)
{
struct hostent *hptr;
if((hptr = gethostbyname(hostname)) == NULL)
{
printf("[ERROR] can not analyze hostname : \t%s\n", hostname);
return false;
}
printf("official hostname : \t%s\n", hptr->h_name);
char **pptr;
char str[32] = {0};
for(pptr = hptr->h_aliases; *pptr != NULL; pptr++)
printf(" alias:%s\n",*pptr);
switch(hptr->h_addrtype)
{
case AF_INET:
for(pptr = hptr->h_addr_list; *pptr != NULL; pptr++)
{
inet_ntop(hptr->h_addrtype, *pptr, str, sizeof(str));
printf("address : \t\t%s\n", str);
}
inet_ntop(hptr->h_addrtype, hptr->h_addr, str, sizeof(str));
printf("first address : \t%s\n", str);
break;
default:
printf("unknown address type\n");
break;
}
return true;
}
2.socket 與 IP地址的映射
使用下面2個函數getsockname(),getpeername()。
///getsockname函數用於獲取與某個套接字關聯的本地協議地址。
int getsockname(int sockfd, struct sockaddr *localaddr, socklen_t *addrlen);
///getpeername函數用於獲取與某個套接字關聯的外地協議地址。
int getpeername(int sockfd, struct sockaddr *peeraddr, socklen_t *addrlen);
對於這兩個函數,如果函數調用成功,則返回0,如果調用出錯,則返回-1。
使用這兩個函數,我們可以通過套接字描述符來獲取自己的IP地址和連接對端的IP地址。
TCP
對於服務器來說,在bind以後就可以調用getsockname來獲取本地地址和端口,雖然這沒有什麼太多的意義。getpeername只有在鏈接建立以後才調用,否則不能正確獲得對方地址和端口,所以他的參數描述字一般是鏈接描述字而非監聽套接口描述字。
對於客戶端來說,在調用socket時候內核還不會分配IP和端口,此時調用getsockname不會獲得正確的端口和地址(當然鏈接沒建立更不可能調用getpeername),當然如果調用了bind 以後可以使用getsockname。想要正確的到對方地址(一般客戶端不需要這個功能),則必須在鏈接建立以後,同樣鏈接建立以後,此時客戶端地址和端口就已經被指定,此時是調用getsockname的時機。
/// getpeername 例子, getsocketname類似。
struct sockaddr_in tmp_addr;
socklen_t sock_len = sizeof(struct sockaddr_in);
getpeername(fd_socket, (struct sockaddr *)&tmp_addr, &sock_len);
printf("\n[Info] Close socket : %d : %s, \"%s:%d\".\n",
fd_socket, reason,
(char *)inet_ntoa(tmp_addr.sin_addr), tmp_addr.sin_port);