Socket编程中常见的数据结构及转换函数

Socket编程中常见的数据结构及转换函数

引言:本篇笔记第一部分介绍socket套接字编程中常见的数据结构,第二部分介绍网络字节顺序、主机与网络字节顺序转换函数、IP地址转换函数。


一、Socket编程中常见的网络数据结构

  下面介绍到的函数,都定义在netinet/in.h中,在ubuntu14.04下,其存储位置为/usr/include/netinet/in.h,可以cat打印其内容查看。

1.1、struct sockaddr

  struct sockaddr是linux网络编程接口中用来表示IP地址的标准结构体,bind、connect等函数中都会用到这个结构体,这个结构体是兼容Ipv4和Ipv6的。在实际编程中,这个结构体会被一个struct sockaddr_in 或者struct sockaddr_in6所填充。

 struct sockaddr{
    unsigned short sa_family; /* address族, AF_XXX*/
    char sa_data[14];         /*14bytes的协议地址*/
    }
  • sa_family :一般来说都是AFINEF,用以指代TCP/IP协议簇的地址。
  • sa_data:包含电脑IP、端口和套接字的数目,它里面的数据是杂融在一起的。

1.2、in_addr_t

typedef uint32_t in_addr_t;   /*网络内部用来表示IP地址的类型*/
  • in_addr_t :网络内部用来表示IP地址的类型,是32位二进制数字

1.3、struct in_addr

  struct in_addr{
        in_addr_t s_addr;
    }
  • s_addr:这个存储的内容还是IP地址,为32位二进制数字,保障层次的一致性。

1.4、struct sockaddr_in

  这个是Ipv4的标准格式,提供了方便的手段来访问socket address(struct sockaddr)结构中的每一个元素。

 struct sockaddr_in
 {
   __SOCKADDR_COMMON (sin_);
    in_port_t sin_port;         /* Port number.  */
    struct in_addr sin_addr;        /* Internet address.  */
    /* Pad to size of `struct sockaddr'.  */
    unsigned char sin_zero[sizeof (struct sockaddr) -
               __SOCKADDR_COMMON_SIZE -
               sizeof (in_port_t) -
               sizeof (struct in_addr)];
};
  • _SOCKADDR_COMMON ( ):是一个宏定义结构,括号里面是它的参数,用以表示tcp/ip协议的版本,sin是ipv4, sin_6是ipv6。

  • unsigned char sin_zero:做减法为了保证这个结构体和struct sockaddr的大小一致。

1.5、struct sockaddr_in6

  这个是Ipv6的标准格式,提供了方便的手段来访问socket address(struct sockaddr)结构中的每一个元素。

   struct sockaddr_in6
  {
        __SOCKADDR_COMMON (sin6_);
        in_port_t sin6_port;    /* Transport layer port # */
        uint32_t sin6_flowinfo; /* IPv6 flow information */
        struct in6_addr sin6_addr;  /* IPv6 address */
        uint32_t sin6_scope_id; /* IPv6 scope-id */
  };

  总结来说,struct sockaddr是linux网络编程接口中用来表示IP地址的标准结构体,bind、connect等函数中都会用到这个结构体,这个结构体是兼容Ipv4和Ipv6的。在实际编程中,这个结构体会被一个struct sockaddr_in 或者struct sockaddr_in6所填充


二、基本转换函数

  在各种计算机体系中,对于字节、字等的存储机制有所不同,因为引发计算机通信领域中一个很重要的问题,即通信双方交流的信息单元(比特、字节、字、双字等等)应该以什么样的顺序进行传送。如果不达成一致的规则,通信双方将无法进行正 确的编/译码从而导致通信失败。关于大小端及验证方式,可以查看计算机存储的大小端模式解析。我们这里介绍网络字节顺序、主机与网络字节顺序转换函数、IP地址转换函数,为介绍网络编程核心API铺垫。

2.1、网络字节顺序

  因为每一个机器内部对变量的字节存储顺序不同(大端:高位字节排放在内存的低地址端,低位字节存放在内存高地址端),而网络传输的数据大家是一定要统一的。所以对于内部字节表示顺序和网络字节顺序不同的机器,就一定要对数据进行转换,保证其可以正确解析。

对内部字节顺序和网络字节顺序相同的机器,同样调用转换函数,系统函数自己判定是否需要转换。

2.2、主机与网络字节序转换函数

  通常使用的有两种数据类型,短型(两个字节,如端口号)和长形(四个字节,如Ipv4地址)。在将数据发送到Internet之前,一定要把它的字节顺序从主机字节顺序,转换到网络字节顺序。下面这几款转换函数可以满足基本的需求:

Socket编程中常见的数据结构及转换函数_第1张图片
图1、主机与网络字节顺序转换函数

  在这些函数中,h理解为host主机、to即转换到、n为internet网络、s为short即短整形、l为long即整形。htons()即将一个短整形数据,从主机字节顺序转换到网络字节顺序。

2.3、与IP地址转换有关的函数

  我们习惯用点分十进制的表达方式来表示IP地址,如192.168.1.110,还是需要转换为一个无符号长整型,以便将其添加进表示IP地址的标准结构体,linux也提供了很多用于转换IP地址的函数,同样,可以查看其man手册:

Socket编程中常见的数据结构及转换函数_第2张图片
图2、与IP地址格式转换相关的函数

  这里选用了常用的几款,其测试代码如下:

/******************************************************
*时间:2018.02.05日
*内容:测试IP地址转换函数
*问题:
******************************************************/

#include
#include 
#include 
#include 

#define MYIP "192.168.1.120"

int main(void)
{

/*******************************************************
*代码段1:测试IP转换函数:in_addr_t inet_addr(const char*p)
*结   果:    0x  78   01   a8   c0
*                 120   1  168  192      
*注   意:输出统一使用大端模式,即网络字节序
*******************************************************/
    #if 0
    in_addr_t addr = 0; 
    addr = inet_addr(MYIP);
    printf("addr = 0x%x\n",  addr);
    #endif

/**********************************************************
*名   称 :inet_pton
*功   能 :convert IPv4 and IPv6 addresses from text to binary form
*函数原型:int inet_pton(int af, const char *src, void *dst);
*执行结果:0x78 01 a8 c0
*备   注:结构体初始化,需要注意{}
*********************************************************/
    #if 0
    struct in_addr addr = {0};
    int ret = 0;
    ret =  inet_pton(AF_INET, MYIP, &addr);
    if(ret != 1)
    {
        printf("inet_pton error!");
    }   
    else
    {
        printf("addr = 0x%x\n", addr.s_addr);
    }

    #endif

/**********************************************************
*名   称 :inet_ntop
*功   能 :convert IPv4 and IPv6 addresses from  binary to text form
*函数原型:const char *inet_ntop(int af, const void *src,
                     char *dst, socklen_t size);
*执行结果:ip addr = 192.168.1.120
*备   注:
***********************************************************/

    struct in_addr addr = {0};
    char buf[20] = {0};

    addr.s_addr = 0x7801a8c0;

    inet_ntop(AF_INET, &addr, buf, sizeof(buf));
    printf("ip addr = %s.\n", buf);
    return 0; 
}

小结:本篇笔记介绍了与socket编程相关的数据结构及基本的转换函数。

参考内容:

1、linux man手册
2、《unix网络编程卷一》

纠错与建议
邮箱:[email protected]


你可能感兴趣的:(网络编程)