array(2) { ["docs"]=> array(10) { [0]=> array(10) { ["id"]=> string(3) "428" ["text"]=> string(77) "Visual Studio 2017 单独启动MSDN帮助(Microsoft Help Viewer)的方法" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(8) "DonetRen" ["tagsname"]=> string(55) "Visual Studio 2017|MSDN帮助|C#程序|.NET|Help Viewer" ["tagsid"]=> string(23) "[401,402,403,"300",404]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511400964" ["_id"]=> string(3) "428" } [1]=> array(10) { ["id"]=> string(3) "427" ["text"]=> string(42) "npm -v;报错 cannot find module "wrapp"" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(4) "zzty" ["tagsname"]=> string(50) "node.js|npm|cannot find module "wrapp“|node" ["tagsid"]=> string(19) "[398,"239",399,400]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511400760" ["_id"]=> string(3) "427" } [2]=> array(10) { ["id"]=> string(3) "426" ["text"]=> string(54) "说说css中pt、px、em、rem都扮演了什么角色" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(12) "zhengqiaoyin" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511400640" ["_id"]=> string(3) "426" } [3]=> array(10) { ["id"]=> string(3) "425" ["text"]=> string(83) "深入学习JS执行--创建执行上下文(变量对象,作用域链,this)" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(7) "Ry-yuan" ["tagsname"]=> string(33) "Javascript|Javascript执行过程" ["tagsid"]=> string(13) "["169","191"]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511399901" ["_id"]=> string(3) "425" } [4]=> array(10) { ["id"]=> string(3) "424" ["text"]=> string(30) "C# 排序技术研究与对比" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(9) "vveiliang" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(8) ".Net Dev" ["catesid"]=> string(5) "[199]" ["createtime"]=> string(10) "1511399150" ["_id"]=> string(3) "424" } [5]=> array(10) { ["id"]=> string(3) "423" ["text"]=> string(72) "【算法】小白的算法笔记:快速排序算法的编码和优化" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(9) "penghuwan" ["tagsname"]=> string(6) "算法" ["tagsid"]=> string(7) "["344"]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511398109" ["_id"]=> string(3) "423" } [6]=> array(10) { ["id"]=> string(3) "422" ["text"]=> string(64) "JavaScript数据可视化编程学习(二)Flotr2,雷达图" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(7) "chengxs" ["tagsname"]=> string(28) "数据可视化|前端学习" ["tagsid"]=> string(9) "[396,397]" ["catesname"]=> string(18) "前端基本知识" ["catesid"]=> string(5) "[198]" ["createtime"]=> string(10) "1511397800" ["_id"]=> string(3) "422" } [7]=> array(10) { ["id"]=> string(3) "421" ["text"]=> string(36) "C#表达式目录树(Expression)" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(4) "wwym" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(4) ".NET" ["catesid"]=> string(7) "["119"]" ["createtime"]=> string(10) "1511397474" ["_id"]=> string(3) "421" } [8]=> array(10) { ["id"]=> string(3) "420" ["text"]=> string(47) "数据结构 队列_队列实例:事件处理" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(7) "idreamo" ["tagsname"]=> string(40) "C语言|数据结构|队列|事件处理" ["tagsid"]=> string(23) "["246","247","248",395]" ["catesname"]=> string(12) "数据结构" ["catesid"]=> string(7) "["133"]" ["createtime"]=> string(10) "1511397279" ["_id"]=> string(3) "420" } [9]=> array(10) { ["id"]=> string(3) "419" ["text"]=> string(47) "久等了,博客园官方Android客户端发布" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(3) "cmt" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511396549" ["_id"]=> string(3) "419" } } ["count"]=> int(200) } 222 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 \n", ip_buf);
    printf("net: %x \n", 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 \n", my_addr.s_addr);
    printf("ip : %s \n", 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 \n", p ->h_name);
    
    int index ;
    char** pp  = p -> h_aliases ;
    for(index = 0 ; pp[index] != NULL; index ++ )
    {
        printf("alias : %s \n", pp[index]);
    }
    
    printf("ip type : %d\n", p ->h_addrtype);
    
    printf("addr len : %d \n", 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 \n", 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\n",(char*)(&a)[0]);
}

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

总结

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

相关文章: