一、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.
然后是返回值:
失败返回空。否则返回值指向我们需要的信息的那个结构体。
RETURN VALUE
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 ", __func__); char host[256] = {0}; if(gethostname(host, sizeof(host)) < 0) { perror("gethostname"); return -1; } printf("host:%s ", 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 ", 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的对方的地址
#include <sys/socket.h>
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 ", 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 ", 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 ", ntohs(addr2.sin_port), inet_ntoa(addr2.sin_addr)); deal_connect(conn); // 用来处理连接的函数 } 。。。。。。