天天看點

關于 getsockname、getpeername和gethostname、gethostbyname一、gethostname,gethostbyname的用法二、關于getsockname和getpeername

一、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); // 用來處理連接配接的函數
    }
。。。。。。