一、gethostname,gethostbyname的用法
這兩個函數可以用來擷取主機的資訊。
gethostname:擷取主機的名字
gethostbyname:通過名字擷取其他的資訊(比如ip)
1.gethostname:
man手冊裡面的解釋(部分):
#include <unistd.h>
int gethostname(char *name, size_t len);
int sethostname(const char *name, size_t len);
DESCRIPTION
These system calls are used to access or to change the hostname of the
current processor.
RETURN VALUE
On success, zero is returned. On error, -1 is returned, and errno is
set appropriately.
2.gethostbyname:
#include <netdb.h>
extern int h_errno;
struct hostent *gethostbyname(const char *name);
可以看到擷取的内容儲存在一個指針裡面。下面我們來看這個指針指向的内容:
The hostent structure is defined in <netdb.h> as follows:
struct hostent {
char *h_name; /* official name of host */
char **h_aliases; /* alias list */
int h_addrtype; /* host address type */
int h_length; /* length of address */
char **h_addr_list; /* list of addresses */
}
#define h_addr h_addr_list[0] /* for backward compatibility */
The members of the hostent structure are:
h_name The official name of the host.
h_aliases
An array of alternative names for the host, terminated by a NULL
pointer.
h_addrtype
The type of address; always AF_INET or AF_INET6 at present.
h_length
The length of the address in bytes.
h_addr_list
An array of pointers to network addresses for the host (in net‐
work byte order), terminated by a NULL pointer.
h_addr The first address in h_addr_list for backward compatibility.
然後是傳回值:
失敗傳回空。否則傳回值指向我們需要的資訊的那個結構體。
The gethostbyname() and gethostbyaddr() functions return the hostent
structure or a NULL pointer if an error occurs. On error, the h_errno
variable holds an error number. When non-NULL, the return value may
point at static data, see the notes below.
執行個體:
#include<stdio.h>
#include<unistd.h>
#include<netdb.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
int main()
{
printf("%s() +++ hello\n", __func__);
char host[256] = {0};
if(gethostname(host, sizeof(host)) < 0)
{
perror("gethostname");
return -1;
}
printf("host:%s\n", host);
struct hostent *myhost = NULL;
if(!(myhost = gethostbyname(host)))
{
perror("gethostbyname");
return -2;
}
int i = 0;
while(myhost && myhost->h_addr_list[i])
{
printf("ip%d:%s\n", i+1, inet_ntoa(*(struct in_addr*)myhost->h_addr_list[i]));
i++;
}
return 0;
}
運作:
xcy@xcy-virtual-machine:~/test/gethost$ ./a.out
main() +++ hello
host:xcy-virtual-machine
ip1:127.0.1.1
二、關于getsockname和getpeername
1.getsockname:擷取一個套接字的名字。擷取本地的位址和端口資訊。
#include <sys/socket.h>
int getsockname(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
失敗傳回-1,成功傳回0。addr是輸入參數,addrlen是輸入輸出參數
2.getpeername:擷取socket的對方的位址
int getpeername(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
失敗傳回-1,成功傳回0。addr是輸入參數,addrlen是輸入輸出參數
注意:
1)對于server來說:
bind以後就可以調用getsockname來擷取本地位址和端口了,隻不過這樣沒啥意義,因為就是自己綁定的。
隻有在accept以後(就是有連接配接之後才)才能用getpeername擷取client的ip和端口。(client的ip和port也可以在accept函數的第二個參數中帶出)
2)對于client來說:
建立socket并不會配置設定ip和端口。用getsockname擷取出來的資料全是0.
在連接配接(connect)之後才可以用getsockname擷取自己的ip和端口。也可以用getpeername擷取伺服器的。
3.如何使用:僞代碼
用戶端代碼:
......
if(connect(sockfd, (struct sockaddr*)&addr, sizeof(addr)) < 0)
{
perror("connect");
return -2;
}
// 在連接配接以後才能擷取
struct sockaddr_in addr2;
socklen_t len = sizeof(addr2); //
//if(getsockname(sockfd, (struct sockaddr*)&addr2, &len) < 0) // 這個是擷取自己的ip和端口
if(getpeername(sockfd, (struct sockaddr*)&addr2, &len) < 0) // 這個是擷取連接配接方的
{
perror("getsockname");
return -3;
}
printf("Get: port:%d, ip:%s\n", ntohs(addr2.sin_port), inet_ntoa(addr2.sin_addr));
......
服務端代碼:
。。。// 前面有bind,listen等動作,這裡隻處理連接配接的
while(1)
{
int conn = accept(listenfd, (struct sockaddr*)&connaddr, &len);
if(conn < 0)
{
perror("accept");
return -4;
}
// 這裡的connaddr就跟下面getpeername擷取的一樣
char strip[64] = {0};
char *ip = inet_ntoa(connaddr.sin_addr);
strcpy(strip, ip);
printf("new client connect,ip:%s, port:%d\n", strip,ntohs(connaddr.sin_port));
struct sockaddr_in addr2;
socklen_t len = sizeof(addr2);
// if(getsockname(conn, (struct sockaddr*)&addr2, &len) < 0) // 這個是擷取自己的ip和端口
if(getpeername(conn, (struct sockaddr*)&addr2, &len) < 0) // 這個是擷取連接配接方的。這樣其實跟accept參數帶出來的資料是一樣的
{
perror("getsockname");
return -3;
}
printf("get: port:%d, ip:%s\n", ntohs(addr2.sin_port), inet_ntoa(addr2.sin_addr));
deal_connect(conn); // 用來處理連接配接的函數
}
。。。。。。