地址族与数据序列

地址族与数据序列

一、分配给套接字的IP地址和端口号

ip地址分为两类:

  1. IPv4:4字节地址族

  2. IPv6:16字节地址族(为解决2010年时IP地址快要耗尽时提出的标准)

IPv4标准的4字节IP地址分为网络地址和主机地址,且分为ABCDE等类型,一般不会使用已被预约的E类地址。

首先将数据传到主机的网络(网络地址(网络ID))(路由器或交换机),然后再根据主机地址(主机ID)找到目标计算机。

ABCDE五类地址

端口号:端口号是同一操作系统内为区分不同套接字而设置的,不能将1个端口号分配给不同的套接字。

端口号由16位构成,范围为0-65535。0-1023是知名端口,一般分配给特定的应用程序。

虽然端口号不能重复,但TCP套接字和UDP套接字不会共用端口号,所以允许重复。

例如,某TCP套接字使用9190端口,其他TCP套接字不能用9190端口,但UDP套接字可以使用。

二、地址信息的表示

struct sockaddr_in
{
    sa_family_t sin_family; //地址族(Address Family)
    uint16_t sin_port;      //16位TCP/UDP端口号
    struct in_addr sin_addr; //32位IP地址
    char sin_zero[8];       //不使用
};

struct in_addr
{
    in_addr_t s_addr;   //32位IPv4地址
};

POSIX:可移植操作系统接口

struct sockaddr_in serv_addr;
if(bind(serv_sock,(struct sockaddr*) &serv_addr,sizeof(serv_addr))==-1) {
        error_handling("bind() error!");
}

//第一个参数为要分配IP地址和端口号的套接字文件描述符
//第二个参数为sockaddr结构体变量地址值
//第三个参数为第二个结构体变量的长度

struct sockaddr
{
    sa_family_t sin_family; //地址族
    char sa_data[14];       //地址信息
}
//sa_data中应该包含IP地址和端口号,共6字节,剩下的八字节sockaddr_in中sin_zero不使用,填0。

三、网络字节序与地址变换

  1. 字节序与网络字节序

    CPU向内存保存数据的方式有两种,同时,CPU解析数据的方式也有两种。

    大端序:高位字节存放在低位地址

    小端序:高位字节存放在高位地址

    网络字节序统一为大端序。

    Intel和AMD的CPU都采用小端序标准。

    1)大端模式:Big-Endian就是高位字节排放在内存的低地址端,低位字节排放在内存的高地址端。

    (其实大端模式才是我们直观上认为的模式,和字符串存储的模式差类似)

    低地址 ——————–> 高地址 0x12 | 0x34 | 0x56 | 0x78

    2)小端模式:Little-Endian就是低位字节排放在内存的低地址端,高位字节排放在内存的高地址端。

    低地址 ——————–> 高地址 0x78 | 0x56 | 0x34 | 0x12

  2. 字节序转换

      unsigned short htons(unsigned short);
     unsigned short ntohs(unsigned short);
     unsigned long htonl(unsigned long);
     unsigned long ntohl(unsigned long);
    

    其中,htons,h代表主机字节序,n表示网络字节序,htons,可以看做讲主机字节序转换为网络字节序,数据类型为short。

四、网络地址的初始化和分配

  1. 将字符串信息转换为网络字节序的整数型

    #include <arpa/inet.h>
    in_addr_t inet_addr(const char * string);
    //成功时返回32位大端序整数型值,失败时返回INADDR_NONE
    int inet_aton(const char * string, struct in_addr * addr);
    // string : 含有需要转换的IP地址信息的字符串地址值
    // addr : 将保存转换结果的in_addr结构体变量的地址值,自动将结果保存到了addr结构体变量
       
    char * inet_ntoa(struct in_addr adr);
    //成功时返回转换的字符串地址值,失败时返回-1.
    
  2. 网络地址初始化

    struct sockaddr_in addr;
    char * serv_ip = "211.217.168.13"; //声明IP地址字符串
    char * serv_port = "9190";		//声明端口号字符串
    memset(&addr,0,sizeof(addr))		//结构体变量addr的所有成员初始化为0
    addr.sin_family = AF_INET;		//指定地址族
    addr.sin_addr.s_addr = inet_addr(serv_ip); //基于字符串的IP地址初始化
    addr.sin_addr.s_addr = htonl(INADDR_ANY); //利用常数INADDR_ANY分配服务器端的IP地址
    addr.sin_port = htons(atoi(serv_port));	//基于字符串的端口号初始化
       
    

    3.向套接字分配网络地址

    int bind(int sockfd,struct sockaddr * myaddr,socklen_t addrlen);
    

    ​ 2后初始化后再绑定(bind)就好。