当前位置:C++技术网 > 资讯 > SOCKADDR和SOCKADDR_IN的区别分析

SOCKADDR和SOCKADDR_IN的区别分析

更新时间:2016-03-10 23:51:28浏览次数:1+次

    在看本文前,你可以先看看《在Socket编程中,SOCKADDR_IN的后缀IN是什么意思》,了解IN后缀的意思,对于本文的理解是有好处的。
    在Socket编程中,我们使用套接字来通信。套接字==ip:端口。这个套接字我们这里叫做套接字地址,也不知道叫法规不规范,反正是这个意思。有了套接字地址后,我们可以根据这个地址去操作套接字,或者从套接字接收到的信息中提取对方的套接字地址。这样就可以相互通信,通信的基础都是通过套接字来链接的。
    我不说很多理论知识,可以参考学习《计算机网络 谢希仁》的书学习基础理论。这里还是促进大家理解,不是宣讲基本知识。
    套接字(ip:端口)可以唯一确定对方,可以将信息发送给对方。那么这个套接字我们这里还是称之为套接字地址吧,虽然不准确,但是却很好理解。既然是地址,而且这个套接字地址里还含有三部分的信息,分别为地址家族、IP地址和端口。如果让你来设计,你也肯定是用结构体来设计咯。然而,现在有多种网络体系,不只TCP/IP一种哦,所以地址家族就可以有多种可能,不同的地址家族,后面的地址表示方法就不太一样。
    而在设计的时候,就设计了一个通用的socket地址结构体,然后具体的地址家族可以在此基础上重新设计一个结构体或者直接用这个通用的结构体,只不过通用的使用起来比较麻烦。
    我们来看看通用的socket地址结构体声明:

struct sockaddr
{
    unsigned short sa_family;//地址家族
    char sa_data[14];//通用表示形式
};
#define sockaddr SOCKADDR  //各种地址家族的通用地址结构体

    使用通用的socket地址结构体,你要将端口和IP地址想办法存入数组中,这将会是一个很痛苦的过程。为了让地址赋值和取值等操作更加方便,我们要重新设计一个结构。
    当然我们不需要重新设计通用socket地址结构体,而只需要根据需要来设计。我们现在的Internet互联网基本上是基于TCP/IP体系的以太网了。那么我们使用的最多的就是这种网络体系。所以就针对TCP/IP设计了一个结构体sockaddr_in。后缀in也因此而来。后缀in的具体解释看文章开头提到的文章。
    我们看看sockaddr_in的声明:

struct sockaddr_in
{
    short sin_family;//地址家族:TCP/IP
    u_short sin_port;//端口号,2个字节
    struct in_addr sin_addr;//前后推出,此结构体为4个字节,填写IP地址
    char sin_zero[8];//填充字节0,8个字节
};
#define sockaddr_in SOCKADDR_IN  

    从sockaddr_in声明中我们可以看到,sockaddr_in比sockaddr多了两个成员,而且我们可以发现多出了端口和IP两个成员,最后的数组就是多余的填充0的数组。那么这样一来,sockaddr_in和sockaddr结构体的大小就是一样的了。所以你用sizeof求取sockaddr_in和sockaddr的结构体大小是一样的。只是sockaddr_in在使用上更加方便。
    你再仔细看,sockaddr_in的第三个成员sin_addr又是一个结构体,看上去挺复杂麻烦的。这个结构体是in_addr,在前面也说了,in表示的含义了。这个开头的in也是那个意思。in_addr就是专门表示IP地址的。IP地址一般为192.168.1.15这样的,这样的表示方法叫做点分十进制表示法。你可以看到有四个数字,所以你可能会想到用4个字节来存储。可能有时候,你也需要2个双字节来存储,或者直接用一个4字节来存储。直接用四个字节一个值来存储的就是现在的做法,有相关的函数帮我们做好了转换工作,无须担心转换的问题。
    下面看看in_addr的声明:

struct in_addr {
  union {
          struct{u_char s_b1,s_b2,s_b3,s_b4;} S_un_b;//4个单字节结构体
          struct{u_short s_w1,s_w2;}          S_un_w;//2个双字节结构体
          u_long                              S_addr;//1个四字节的IP值
  } S_un;//联合体
};

    这个结构体的声明就是一个联合,分别表示了三种存储方式,共享4字节的内存。那么我们在使用时,一般是用第三个方式,所以我们直接把in_addr看成是一个u_long型值就行了。这样就可以让sockaddr_in结构体看起来简单化了。
    在学习socket编程的人,通常都会被这里的地址绕晕,基本上是sockaddr和sockaddr_in搞不清楚,in_addr(IP地址的结构体联合体类型)和sin_addr(IP地址)搞不清楚。
    所以在写代码的时候,看清楚bind、connent、send、recv、sendto、recvfrom等等函数的地址了。不要将sockaddr_in(SOCKADDR_IN)和sockaddr(SOCKADDR)混用了。同时IP地址类型和IP地址也不要搞混了。我想本文的详细说明,足以让你对这几个概念分的清清楚楚了。