> Linux编程 >

linux网络编程几个基础性知识点

1. 主机字节序、网络字节序
---------------------------------------------------------------------------------------------------
    主机字节序通常采用little-endian,低字节放低地址,高字节放高地址
    网络字节序采用big-endian,低字节放高地址,高字节放低地址
 
    unsigned long htonl(unsigned long host)     // 主机long转网络long
    unsigned long ntohl(unsigned long net)      // 网络long转主机long
    unsigned short htons(unsigned short host)   // 主机short转网络short
    unsigned short ntohs(unsigned short net)    // 网络short转主机short
 
2. 点分十进制字符串IP和32位整型IP
---------------------------------------------------------------------------------------------------
    int inet_aton(const char *cp,struct in_addr *inp)   // 点分十进制字符串IP转32位整型IP,成功返回非0,失败返回0
    char *inet_ntoa(struct in_addr in)                  // 32位整型IP转点分十进制字符串IP
    
    更新的程序用inet_pton和inet_ntop来代替上面两个函数,因为新函数支持ipv4和ipv6
    int inet_pton(int af,const char *src,void *dst)                         // 点分十进制字符串IP转32位整型IP
    const char *inet_ntop(int af,const void *src,char *dst,socklen_t size)  // 32位整型IP转点分十进制字符串IP
 
    上面转换函数都用到的一个结构
        typedef uint32_t in_addt_t;
        struct in_addr{
            in_addr_t s_addr;                           // 网络字节序       
        };
 
3. 主机信息获取
---------------------------------------------------------------------------------------------------
    主机信息主要包括主机名/域名/主机别名、主机IP地址,这些都可以唯一标识一台主机。
    由于通过IP来标识主机的方式可读性太差,所以出现了主机名和域名。
    主机名和域名的区别在于:主机名用于局域网中,而域名用于公网中。
 
    struct hostent *gethostbyname(const char *name)                     // 根据域名或主机名来获取对应的主机信息,从而得到其中的IP地址
    struct hostent *gethostbyaddr(const void *addr,int len,int type)    // 根据IP地址获取主机信息,从而的到其中的域名或主机名
    这两个函数都返回一个hostent结构指针:
    struct hostent{
        char *h_name;                   // 主机的规范名,比如百度的规范名为"www.a.shifen.com"
        char **h_aliases;               // 主机的别名列表(别名可以有多个),比如百度的别名只有一个,就是"www.baidu.com"
        int h_addrtype;                 // 主机IP地址类型,AF_INET/AF_INET6
        int h_length;                   // 主机IP地址长度
        char **h_addr_list;             // 主机的IP地址列表,对于AF_INET类型,列表元素其实就是(struct in_addr *)的结构
        #define h_addr h_addr_list[0]   // 指向主机的首个IP地址
    };
 
    以上2个API只支持IPV4,之后POSIX引入了一个新的API,可以同时支持IPV4和IPV6:
    int getaddrinfo(const char *hostname, const char *service, const struct addrinfo *hints, struct addrinfo **result)
    参数说明:
        @hostname   - 指向一个主机名/域名/地址串(比如"localhost"/"www.baidu.com"/"192.168.9.10")
                    - 当该值设置为NULL时,其含义跟AI_PASSIVE标志相关:
                                当设置了AI_PASSIVE时,返回的套接口地址为INADDR_ANY;
                                当没有设置AI_PASSIVE时,返回的套接口地址为本机环回地址
        @service    - 服务名可以是十进制的端口号字串(比如"3721"),也可以是标准的服务名称(比如"http")
        @hints      - 指向一个struct addrinfo结构,用于设置期望返回的信息类型
                    - 当该值设置为NULL时,意味着对返回的信息类型不做任何限制
        @result     - 用于存放一个返回得到的指针,该指针指向一个struct addrinfo结构的链表
                    - 需要注意的是,这张链表占用的空间需要调用者调用freeaddrinfo进行释放
        @返回值     - 0:成功,同时返回的信息存放在result中   非0:失败,同时调用gai_strerror可以获取对应的错误信息
    这个API同时使用了一个新的addrinfo结构指针用来设置和存放返回的主机信息:
    struct addrinfo
    {
        int ai_flags;                // 附加选项集合(AI_*),通常设置在hints中
        int ai_family;                // 期望的地址族(AF_INET/AF_INET6/AF_UNSPEC),通常设置在hints中
        int ai_socktype;            // 期望的套接字类型(SOCK_STREAM/SOCK_DGRAM),通常设置在hints中
        int ai_protocol;            // 期望的协议类型(一般填0)
        socklen_t ai_addrlen;        // 通常记录在result中,表示满足期望条件的IP地址长度(4/6字节)
        struct sockaddr *ai_addr;    // 通常记录在result中,表示满足期望条件的IP地址
        char *ai_canonname;            // 通常记录在result中,表示满足期望条件的主机信息(只有当hints.ai_flags设置了AI_CANONNAME时才会存在)
        struct addrinfo *ai_next;    // 指向满足期望条件的下一个addrinfo结构
    }
    使用说明:
            [1]. 如果hints.ai_flags设置了AI_NUMERICHOST,则传入的hostname必须是一个地址串,否则报错
            [2]. 如果hints.ai_flags设置了AI_NUMERICSERV,则传入的service必须是一个端口号字符串,否则报错
            [3]. 服务端获取套接口地址信息时通常会设置hints.ai_flags为AI_PASSIVE,并且hostname为NULL,这会返回适合bind和accept的套接字地址
            [4]. 客户端获取套接口地址信息时通常不设置AI_PASSIVE,因为这样返回的套接字地址适合connect和sendto/sendmsg
 
(责任编辑:IT)