zoukankan      html  css  js  c++  java
  • Linux网络编程2——系统函数

    socket信息数据结构

    #include <netinet/in.h>
    
    struct sockaddr 
    {
        unsigned short sa_family;      /*地址族*/
        char sa_data[14];              /*14字节的协议地址,包含该socket的IP地址和端口号。*/
    };
    struct sockaddr_in 
    {
        short int sa_family;           /*地址族*/
        unsigned short int sin_port;   /*端口号*/
        struct in_addr sin_addr;       /*IP地址*/
        unsigned char sin_zero[8];     /*填充0 以保持与struct sockaddr同样大小*/
    };
    struct in_addr
    {
            unsigned long int  s_addr;    /* 32位IPv4地址,网络字节序 */
    };
    #include <netinet/in.h>
    
    tips
    sa_family:
    AF_INET   -> IPv4协议  
    AF_INET6  -> IPv6协议

    注意

    结构体struct in_addr中存放的s_addr,是无符号整型数。实际上32位IPv4地址为点分十进制,每个字节的范围均为0-255,只要高字节大于等于128,那么这个整型数必然为负数,只不过我们这边仅仅关心ip每一位的存储情况,因此此处可以使用无符号数进行存储。

    函数原型1

    SYNOPSIS
           #include <sys/socket.h>
           #include <netinet/in.h>
           #include <arpa/inet.h>
                 
                 
           int inet_aton(const char *cp, struct in_addr *inp);/* 注意,参数inp为传出参数 */
           char *inet_ntoa(struct in_addr in);
    实际上,我们在上篇文章中实现的三个函数是有系统函数可以直接调用的。我们的my_atoh,my_hton合并为系统函数inet_aton,而my_ntoa即为系统函数inet_ntoa。

    举例1

    /*************************************************************************
        > File Name: test.c
        > Author: KrisChou
        > Mail:zhoujx0219@163.com 
        > Created Time: Wed 27 Aug 2014 11:06:11 PM CST
     ************************************************************************/
    
    #include <stdio.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    
    int main(int argc, char *argv[])
    {
        char ip_buf[] = "180.97.33.107";
        struct in_addr my_addr;
        inet_aton(ip_buf,&my_addr);
        printf("ip : %s 
    ", ip_buf);
        printf("net: %x 
    ", my_addr.s_addr);
        return 0;
    }

    运行结果

    [purple@localhost 0827]$ gcc -o test test.c -Wall
    [purple@localhost 0827]$ ./test
    ip : 180.97.33.107
    net: 6b2161b4
    照理,网络字节序是大端存储,应该返回0xb461216b。实际上调用系统函数inet_aton后,就直接在变量my_addr.s_addr的实际内存空间中以二进制形式写入了0xb461216b(其实用位运算,就可以直接操作二进制位,上篇博文有具体实现)。之所以运行结果是0x6b2161b4,是因为我们的主机是小端存储,用printf显示结果是先取低字节。

    举例2

    /*************************************************************************
        > File Name: test1.c
        > Author: KrisChou
        > Mail:zhoujx0219@163.com 
        > Created Time: Wed 27 Aug 2014 11:43:26 PM CST
     ************************************************************************/
    
    #include <stdio.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    
    int main(int argc, char *argv[])
    {
        struct in_addr my_addr;
        my_addr.s_addr = 0xb461216b;
        printf("net: %x 
    ", my_addr.s_addr);
        printf("ip : %s 
    ", inet_ntoa(my_addr));
        return 0;
    }
    运行结果
    [purple@localhost 0827]$ gcc -o test1 test1.c -Wall
    [purple@localhost 0827]$ ./test1
    net: b461216b
    ip : 107.33.97.180
    照理,ip应该输出的是180.97.33.107。其实道理很简单,我们的主机是小端模式存储,而网络字节序是大端模式,当我们把0xb461216b赋值给my_addr.s_addr 时,实际上在内存中存储形式是0x6b2161b4,而inet_ntoa的具体实现时通过位运算直接操纵二进制位的,因此结果就自然输出107.33.97.180。

    函数原型2

    SYNOPSIS
           #include <netdb.h>
           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.

    代码

    /*************************************************************************
      > File Name: my_host.c
      > Author: KrisChou
      > Mail:zhoujx0219@163.com 
      > Created Time: Wed 27 Aug 2014 05:22:46 PM CST
     ************************************************************************/
    
    #include <stdio.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <netdb.h>
    int main(int argc, char* argv[])// exe hostname
    {
        struct hostent* p ;
        p = gethostbyname(argv[1]) ;
        /*
        struct hostent {
            char  *h_name;          
            char **h_aliases;     
            int    h_addrtype;   
            int    h_length;    
            char **h_addr_list;
        }
    #define h_addr h_addr_list[0]
     */ 
        printf("host name: %s 
    ", p ->h_name);
        
        int index ;
        char** pp  = p -> h_aliases ;
        for(index = 0 ; pp[index] != NULL; index ++ )
        {
            printf("alias : %s 
    ", pp[index]);
        }
        
        printf("ip type : %d
    ", p ->h_addrtype);
        
        printf("addr len : %d 
    ", p ->h_length);
        
        pp = p ->h_addr_list ;
        for(index = 0; pp[index] != NULL ; index ++)
        {
            /* 由于h_addr_list是一个字符串指针数组,数组中存放的指针指向一个网络字节序 
                但是系统函数inet_ntoa需要传入的参数是一个结构体,因此需要进行转换。
                pp[index]是一个char*类型的指针,先将其转换为struct in_addr*类型的指针,
                接着去引用,即得到结构体。                                                 */
            printf("ip : %s 
    ", inet_ntoa( *(struct in_addr *)pp[index] ) );
        }
        
        return 0 ;
    }
    运行结果
    [purple@localhost 0827]$ gcc -o myhost my_host.c -Wall
    [purple@localhost 0827]$ ./myhost www.baidu.com
    host name: www.a.shifen.com
    alias : www.baidu.com
    ip type : 2
    addr len : 4
    ip : 180.97.33.107
    ip : 180.97.33.108

    干货

    某年腾讯面试题:

    #include <stdio.h>
    #include <stdlib.h>
    int main()
    {
        int a = 0x61;//97
        printf("%x
    ",(char*)(&a)[0]);
    }

    结果输出61,说明是小端机,先存低字节。

    总结

    切记系统函数无论inet_aton还是inet_ntoa,都是直接以位运算形式实现的,因此其关注的是数据在内存中实际的二进制存储形式。

  • 相关阅读:
    可能会搞砸你的面试:你知道一个TCP连接上能发起多少个HTTP请求吗?
    iOS笔记055
    iOS笔记053- Quartz2D-练习
    iOS笔记052- Quartz2D-绘图
    IOS笔记051-手势使用
    IOS笔记050-事件处理
    IOS笔记049-UITabBarController
    IOS笔记048-数据存储
    IOS笔记047-代理传值和block传值
    IOS笔记046-UIApplication/导航控制器
  • 原文地址:https://www.cnblogs.com/jianxinzhou/p/3940686.html
Copyright © 2011-2022 走看看