TCP/IP网路编程之地址族与数据序列

来源:互联网 发布:php 大端 big endian 编辑:程序博客网 时间:2024/05/15 06:53

IP地址分为IPv4与IPv6 前者是4字节地址族后者是16字节地址族,两者的差异主要是表示IP地址所使用的字节数

IPv4的4字节地址分为网络地址与主机地址,并且分为A、B、C、D、E四种类型


说明:

A类地址的首字节范围是:0-127

B类地址的首字节范围是:128-191

C类地址的首字节范围是:192-223

或者也可以这样分

A类地址的首位是以0开头

B类地址的前两位是以10开头

C类地址的前三位是以110开头

网络地址与主机地址

网络地址是为区分网络而设置的一部分IP地址。

向某个IP地址传输数据时,是先根据网络地址找到,把数据传输到目标网络再根据主机地址将数据传递给目标计算机。其实质过程是向构成目标网络的路由器或者交换机传输数据,其后又接收数据的路由器根据数据中的主机地址向目标传递数据。

 

路由器或者交换机:一种完成外网与本网主机之间的数据交换的物理设备。

 

端口号

在同一操作系统中用于区分不同套接字,无法将一个端口号分配给相同种类的不同套接字,端口号由16位构成,范围是0~65535, 但是0~1023是知名端口,用于分配给特定程序,我们应该使用这之外的端口,另外TCP套接字与UDP套接字可以使用同一端口。

linux系统为例:

struct sockaddr_in

{

      sa_family_t      sin_family;   //地址族                          可取值AF_INET IPv4地址族 AF_INET6 IPv6地址族

      uint16_t            sin_port;     //16位TCP/UDP端口号   16位端口号,需要传递网络字节序

      struct in_addr   sin_addr;    //32位IP地址                    32位IP地址信息,也需要网络字节序,结构体in_addr声明为uint32_t,故直接当作32位整数即可

      char                  sin_zero[8];  //不使用                         为使结构体struct sockaddr_in与结构体sockaddr大小一致的填充

};

该结构体中的 in_addr用来存放32位的IP地址,定义如下

struct in_addr

{

    In_addr_t    s_addr;//32位IP地址

};

在使用时直接使用结构体struct sockaddr_in变量再将其强制转换为sockaddr类型变量即可。

字节序:

因为主机字节序分为大端序与小端序,所以在网络传输数据时约定同一的方式,网络字节序,即大端序

大端序:高位低地址

小端序:高位高地址

如:存储int类型数据0x12345678       最左边为高位,最右边为低位

大端序: 0x12     0x34      0x 56     0x78

高位--------------------------------------------------低位

低地址---------------------------------------------高地址

可见:大端序中最先保存最高位

小端序:0x78      0x56      0x34      0x12

低位--------------------------------------------------高位

低地址---------------------------------------------高地址

可见:小端序中最先保存最低位

Intel系列cpu以小端序保存数据、51系列单片机以大端序保存数据

实际在传输数据时的自动过程:将数据转换成网络字节序传输,将网络字节序的数据转化为主机序接收


由于保存IP地址与端口号的变量需要网络字节序,这需要通过函数:

unsigned short htons (unsigned short);             //h主机字节序 to  n网络字节序  s 两字节short,用于端口的转换整个函数的意思将端口号从主机字节序转化为网络字节序

unsigned  short ntohs(unsigned  short);

unsigned  long htons (unsignedlong);

unsigned  long ntohs (unsignedlong);

函数名中:h表示主机字节序,n表示网络字节序 s表示short, l表示long  以s结尾的函数用于端口号的转换,以l结尾的函数用于IP地址的转换

 

我们平时使用的IP地址为点分十进制的字符串形式,需要将其转化为32位的整数数据

下面两个函数可以帮我们解决这个问题,他们得到32位整数已经是网络字节序了,无需再次转换

in_addr_t inet_addr(const char* string);

int inet_aton(const char *string,struct in_addr *addr);  改函数的第二个参数直接传递结构体struct sockaddr_in变量的成员sin_addr的地址即可,函数将得到的网络字节序的IP地址直接存入结构体变量中

函数char *inet_ntoa(struct in_addr adr);可将传入的整数型IP地址转换为字符串格式并返回,如果需要保存返回的点分十进制的字符串形式ip应该将返回的字符串拷贝(strcpy函数)到自定义的空间中,因为一旦再次调用,原来返回的字符串将被覆盖

 

网络地址的初始化

定义结构体sockaddr_in 变量,然后将变量清零(memset、或bzero)  接着向结构体变量指定地址族、赋值网络字节序的ip、网路字节序端口号

注意:点分十进制的IP与端口号是字符串形式,  ip地址.通过上面讲的两个函数转换为网络字节序的整数后赋值给结构体变量的成员,端口号通过函数atoi转换为整数后再通过函数htons转化为网络字节序后赋值给结构体变量成员

另外,当是为服务器设置ip地址时,可直接使用常数INADDR_ANY自动获取运行服务器端计算机IP地址,表示监听指定端口的所有网卡/IP收到的数据

回送地址:127.0.0.1 一般用于网络软件测试以及本地机进程间通信

0 0