《TCP/IP网络编程》第3章 地址族与数据序列

3.1 分配给套接字的IP地址与端口号

    IP是InternetProtocol(网络协议)的简写,是为收发网络数据而分配给计算机的值

    端口号并非赋予计算机的值,而是为区分程序中创建的套接字而分配给套接字的序号

1.       网络地址(Internet Address)

  • IPv4 4字节地址族
  • IPv6 16字节地址族

    IPv4标准的4字节IP地址分为网络地址和主机(指计算机)地址,且分为A、B、C、D、E等类型。



    关注:路由器与交换机的作用

2.       用于区分套接字的端口号

    计算机中一般配有NIC(NetworkInterface Card,网络接口卡)数据传输设备。

    通过NIC向计算机内部传输数据时会用到IP。操作系统负责把传递到内部的数据适当分配给套接字,这时就要利用端口号。

    端口号就是在同一操作系统内为区分不同套接字而设置的,因此无法将1个端口号分配给不同套接字。

    另外,端口号由16位构成,可分配的端口号范围是0~65535。但0~1023是知名端口(Well-Known  PORT),一般分配给特定应用程序。

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

    总之,数据传输目标地址同时包含IP地址和端口号,只有这样,数据才会被传输到最终的目的应用程序(应用程序套接字)。

3.2 地址信息的表示

    应用程序中使用的IP地址和端口号以结构体的形式给出了定义。

1.       表示IPv4地址的结构体

struct sockaddr_in
{
    sa_family_t       sin_family;  // 地址族

    uint16_t          sin_port;     //16位TCP/IP端口号,网络字节序

    struct in_addr    sin_addr;     // 32位IP地址,网络字节序

    char              sin_zero[8];  // 不使用,仅为使sockaddr_in与sockaddr结构体保持一致
};

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

      

    如果使用int32_t类型的数据,就能保证在任何时候都占用4字节,即使将来用64位表示int类型也是如此。

    sockaddr_in 结构体变量地址值将以如下方式传递给bind函数:

struct sockaddr
{
    sa_family_t       sin_family;       //  地址族
    char              sa_data[14];      // 地址信息
};

    此结构体成员sa_data保存的地址信息中需包含IP地址号和端口号,剩余部分应填充0,这也是bind函数的要求。

    sockaddr_in是保存IPv4地址信息的结构体,而sockaddr并非只为IPv4设计。所以仍需单独指定sin_family。

3.3 网络字节序与地址转换

    代表CPU数据保存方式的主机字节序(HostByte Order)在不同CPU中也各不相同。在通过网络传输数据时,约定:统一使用网络字节序(NetworkByte Order),即大端字节序。

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

    htons中的h代表主机(host)字节序;n代表网络(network)字节序。

    s指的是short,l指的是long。(Linux中long类型占用4个字节)

    通常,以s作为后缀函数用于端口号转换,以l作为后缀函数用于IP地址转换。

    问:数据传输过程中都需要转换吗?

    答:除了向sockaddr_in结构体变量填充数据外,其他情况无需考虑字节序问题。

3.4 网络地址的初始化与分配

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

    sockaddr_in中保存IP地址信息的成员为32位整数型,因此,为了分配IP地址,需要将点分十进制(DottedDecimal Notation)的IP地址化为32位整数型数据。

#include<arpa/inet.h>
in_addr_t  inet_addr(const char *string); 
//成功时返回32位大端序整数型值,失败时返回INADDR_NONE

    该函数将字符串形式的IP地址转换成32位大端序(网络序)整数型IP地址。还可检测无效IP地址。 

#include<arpa/inet.h>
int  inet_aton(const  char * string,  struct in_addr *addr); 

    该函数与inet_addr函数功能相同,但其利用了in_addr结构体,使用频率很高;与inet_aton作用相反的函数:

#include<arpa/inet.h>
char* inet_ntoa(struct  in_addr  addr);

注意:调用时应将字符串信息复制到其他内存空间。(通过strcpy函数)

2.       常用的网络地址初始化方法

    atoi函数把字符串转换成整型。

3.       INADDR_ANY

    每次创建服务器端套接字都要输入IP地址会有些繁琐,此时可如下初始化地址信息:

struct sockaddr_inaddr;
......
addr.sin_addr.s_addr= htonl(INADDR_ANY);

    若采用这种方式,则可自动获取运行服务器端的计算机IP地址,不必亲自输入。而且,若同一计算机中已分配多个IP地址(多宿主(Multi-homed)计算机,一般路由器属于这一类),则只要端口号一致,就可以从不同IP地址接收数据。(实际IP地址的个数与计算机中安装的NIC的数量相等,若只有一个NIC,则直接使用INADDR_ANY)

    127.0.0.1是回送地址(loopback address),指的是计算机自身IP地址。若用实际IP地址代替此地址也能正常运转。

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

#include<sys/socket.h>
int bind(int sockfd, structsockaddr *myaddr, socklen_t addrlen);

-sockfd:要分配地址信息(IP地址和端口号)的套接字文件描述符;

-myaddr: 存有地址信息的结构体变量地址值;

-addrlen: 第二个结构体变量的长度;


发布了28 篇原创文章 · 获赞 2 · 访问量 5156
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章