• Socket 介绍


    IPV4 套接字地址结构

    <netstat/in.h>
    struct in_addr {
      in_addr_t   s_addr;           /*u32-bit IPv4 address;network byte ordered*/
    };
    
    struct sockaddr_in {
      uint8_t         sin_len;      /* length of structure (16) */
      sa_family_t     sin_family;   /* u8-bit(support length) or u16-bit(not support)*/
      in_port_t       sin_port;     /* u16-bit TCP or UDP port number;network byte ordered*/
      struct in_addr  sin_addr;     /* in_addr structure*/
      char            sin_zero[8];  /* unused */
    };
    
    

    sin_len字段简化了处理不同长度套接字地址结构的情况。用于内核处理不同协议的套接字。除了路由套接字之外,我们不使用这个字段。
    有四个函数将套接字地址从进程传给内核bind,connect,sendto,sendmsg,这些函数通过参数显式设置sin_len参数;另外五个函数将套接字地址从内核传给进程,accept,recvform,recvmsg,getpeername,getsockname,sin_len在返回进程之前就被设置。
    POSIX只需要sin_family,sin_addr,sin_port。大多数实现都增加了sin_zero成员,因此所有的socket address结构都至少为16字节。IPV4地址及端口号都存储为网络字节序,一般使用时都要与主机字节序相互转换。
    32位IPV4地址有两种访问方式:sin_addr,将IPV4地址视为in_addr结构;sin_addr.s_addr将IPV4地址视为in_addr_t(uint32_t),当传参数时,应当正确使用IPV4地址。早期实现中,in_addr结构是多个结构的union,允许访问32位中的每个字节。用于A,B,C类型网络获取地址。随着子网出现以及无类型寻址,union结构被废弃。sin_zero字段不使用,总是设为0。实际上在填充sockaddr_in之前,将整个结构填为0。

    套接字地址总是引用传参。但是套接字函数会处理多种协议。因此提出了通用的套接字地址结构。

    <sys/socket.h>
    struct sockaddr {
      uint8_t      sa_len;
      sa_family_t  sa_family;    /* address family: AF_xxx value */
      char         sa_data[14];  /* protocol-specific address */
    };
    
    

    套接字函数都使用通用套接字地址作为参数。一般情况下这样使用:

    int bind(int, struct sockaddr *, socklen_t); /*prototype*/
    
    struct sockaddr_in  serv;      /* IPv4 socket address structure */
    /* fill in serv{} */
    bind(sockfd, (struct sockaddr *) &serv, sizeof(serv));
    
    

    IPV6套接字地址结构 (todo)

    使用了新的通用结构,支持所有地址类型

    struct sockaddr_storage {
      uint8_t      ss_len;       /* length of this struct (implementation dependent) */
      sa_family_t  ss_family;    /* address family: AF_xxx value */
      /* implementation-dependent elements to provide:
       * a) alignment sufficient to fulfill the alignment requirements of
       *    all socket address types that the system supports.
       * b) enough storage to hold any type of socket address that the
       *    system supports.
       */
    };
    
    

    sockaddr_storage支持对齐需求。除了ss_family和ss_len,其他字段都是不透明的,需要根据ss_family进行转换。

    套接字地址结构比较

    a
    IPV4和IPV6结构是定长的,Unix domain和datalink结构是变长的。因此当我们向套接字函数传递套接字指针时,需要传递长度。从4.3BSD开始,所有套接字地址都增加了长度字段,可以将长度包含着结构体之中而不用向函数传递参数。

    Value-Result参数

    前面提到,套接字地址结构通过引用传递。长度参数的传递方式取决于传递方向。并且,
    bind(), connect(), sendto()从进程将结构指针以及长度值传给内核,因此内核知道从哪拷贝多少数据。
    accept(), recvfrom(), getsockname(),getpeername()从内核传给进程,结构及长度都使用指针传递。当函数调用时,进程告诉内核结构的长度;当返回时,内核告诉进程实际存储的数据长度。另外两个函数recvmsg, sendmsg将长度作为结构成员而不是参数。

    字节序

    小端:低位在低地址;大端:高位在低地址。网络字节序使用大端。
    a

    #include <netinet/in.h>
     
    uint16_t htons(uint16_t ) ; 
    uint32_t htonl(uint32_t ) ;/*Both return: value in network byte order*/
    
    uint16_t ntohs(uint16_t ) ; 
    uint32_t ntohl(uint32_t ) ; /*Both return: value in host byte order*/
    /*do not care about the actual byte order*/
    

    字符串与地址转换函数

    #include <arpa/inet.h> 
    int inet_aton(const char *strptr, struct in_addr *addrptr); /*Returns: 1 if string was valid, 0 on error*/
    in_addr_t inet_addr(const char *strptr);/*Returns: 32-bit binary network byte ordered IPv4 address; INADDR_NONE if error,deprecated*/
    char *inet_ntoa(struct in_addr inaddr);/*Returns: pointer to dotted-decimal string*/
    

    这三个函数转换IPV4地址的字符串与32位网络字节序值。inet_aton将字符串转换为32位网络字节;inet_addr发生错误时将返回INADDR_NONE(0xffffffff),因此无法处理255.255.255.255,此函数已经废弃;inet_ntoa返回322位网络字节对应的字符串,返回值在静态内存中,此函数是不可重入的。

    #include <arpa/inet.h>
     
    int inet_pton(int family, const char *strptr, void *addrptr); /*Returns: 1 if OK, 0 if input not a valid presentation format, -1 on error*/
    
    const char *inet_ntop(int family, const void *addrptr, char *strptr, size_t len); /*Returns: pointer to result if OK, NULL on error*/
    
    

    这两个函数可以处理IPV4或IPV6地址。p代表presentation,n代表numeric。family是AF_INET,AF_INET6之一。‌inet_ntop的len参数指定缓冲区的长度,使用两个宏来指定大小:

    #define INET_ADDRSTRLEN       16       /* for IPv4 dotted-decimal */
    #define INET6_ADDRSTRLEN      46       /* for IPv6 hex string */
    
  • 相关阅读:
    slf4j + log4j 记录日志
    Executors介绍
    Java集合(JDK1.6.0_45)
    Java多线程系列目录(共43篇)
    线程池体系
    FutureTask
    23种设计模式分类
    结构型 之 适配器模式
    信号量Semaphore详解以及应用
    Excel格式转化工具
  • 原文地址:https://www.cnblogs.com/zyfgs2012/p/4074528.html
Copyright © 2020-2023  润新知