上一篇文章介绍了套接字的创建过程,这篇文章主要讨论分配给套接字的IP地址和端口号的相关知识。

IP地址和端口号

IP(Internet Protocol,网络协议)地址是收发网络数据而分配给计算机的值,端口号则并非赋予计算机的值,而是为了区分计算机程序所创建的不同套接字而分配给套接字的编号。

网络地址

IP地址分为如下两类,其中,IPv6是为了应对2010年前后IP地址耗尽的问题而提出的新标准。不过,目前普遍使用的主要还是IPv4,IPv6的普及可能还需要一段时间。

  IPv4(Internet Protocol version 4)  4字节地址族

  IPv6(Internet Protocol version 6)  16字节地址族

IPv4标准的4字节IP地址由网络地址和主机地址组成,其中网络地址主要分为A、B、C、D等类型,结构如下:

IPv4地址族

IP地址为什么要分为网络地址和主机地址?网络地址是为了区分不同网络而设置的一部分IP地址,试想,如果4字节的IP地址全都是主机地址,那么计算机间的通信寻路将会变得异常低效。而网络地址的加入将通信寻路过程分为了两个部分,首先锁定有效的网络地址,再查找主机地址,有效提高了通信效率。例如,某主机向203.211.172.103和203.211.217.202传输数据,其中,203.211.172和203.211.217为网络地址。从图中可以看出,网络地址的节点是由路由器或交换机组成的,接收数据的路由器再根据数据中的主机地址向目标主机传输数据。

上面提到的网络地址是203.211.172和203.211.217,那么如何区分它们的类型?我们只需要关注IP地址的第一个字节的数值即可:

  A类地址首字节范围:0~127   0000 0000 ~ 01111 11111

  B类地址首字节范围:128~191   1000 0000 ~ 10111 11111

  C类地址首字节范围:192~223   1100 0000 ~ 11011 11111

另外,根据上面不同类型网络地址所占的字节数,能够知道A类地址是最宝贵的,因为它拥有的IP地址资源最为丰富。一个A类地址相当于256个B类地址,同样的,一个B类地址相当于256个C类地址。

端口号

IP地址用于区分计算机,只要有IP地址就能够向目标主机传输数据,但仅此并不能确定具体程序。比如,此时计算机中正运行着聊天程序和浏览器程序,那么该计算机如何决定将接收到的网络数据发给哪个程序呢?

计算机中一般都配有NIC(Network Interface Card,网络接口卡)数据传输设备,通过NIC向计算机内部传输数据时需要用到IP地址。而操作系统负责将内部数据具体分配给套接字,这时就需要用到端口号来作为区分。整个数据的分配过程如下:

端口号就是同一操作系统中为了区分不同套接字而设置的,因此无法将一个端口号分配给不同的套接字(由于TCP套接字和UDP套接字不会共用端口号,可以重复)。端口号由16位组成,范围0~65535,但0~1023是特定程序使用的知名端口号,所以应当使用此范围之外的值。

地址信息的表示

之前的文章中有提到sockaddr_in和sockaddr,下面给出相关的结构体定义

//IPv4地址结构
struct sockaddr_in
{
sa_family_t sin_family; //地址族
uint16_t     sin_port; //16位端口号,网络序保存
struct in_addr sin_addr; //32位IP地址,网络序保存
char        sin_zero[]; //保留
} //通用地址结构
struct sockaddr
{
sa_family_t sin_family; //地址族
char sa_data[]; //地址信息
} struct in_addr
{
in_addr_t s_addr; //32位IPv4地址
}

以上结构体定义中涉及到的数据类型如uint16_t、in_addr_t等,可参考POSIX(Portable Operating System Interface,可移植操作系统接口)。之所以有这些定义,是考虑到移植性的结果,如uint16_t,不论是在32位系统中还是在64位系统中其对应数据类型均是16位无符号整形。POSIX中的一些数据类型定义如下:

之前的文章中有提到sockaddr_in和sockaddr的区别的问题,结合上面的结构体定义可知,sockaddr_in是IPv4地址信息专用的结构体;而sockaddr则是兼容除IPv4地址信息之外的结构体(不过从地址信息字节大小14个字节来看,似乎并不兼容IPv6)。

网络字节序与地址转换

字节序,简单来说就是一个数据的高低字节在内存中的存储及解析方式。字节序分为如下两种类型:

  大端序(Big Endian):高位字节存放在低位地址

  小端序(Little Endian):低位字节存放在低位地址

单字节数据的大小端存储方式并没有区别,多字节数据的大小端存储方式则截然不同。如一个4字节整型值0x12345678的高字节数据0x12,大端存储时在内存的低地址端,而小端存储则正好相反:

大端序存储和小端序存储

为什么计算机通信需要字节序转换?如果发生数据交换的两台计算机有不同的字节序存储方式会发生什么?

不同字节序的计算机发生数据交换时引发的错误

正如上图所发生的那样,大端序系统的数据传输到小端序系统,原来的数据0x1234被错误地解析为0x3412。这显然不是我们所期望得到的结果,因此当需要在不同的计算机间传输数据时,我们要时刻铭记字节序的转换。而考虑到程序的可移植性,即使我们已知通信双方主机拥有相同字节序,我们仍需做字节序转换的操作。进一步,当有数据需要持久化并且可能在其他主机上恢复时,我们也需要考虑字节序转换的操作。

实际上,在网络编程中,我们只需要考虑向sockaddr_in结构体变量填充数据时的字节序转换,而真正传输数据的字节序转换是底层机制自动完成的。书中的这段描述应该有问题,字节序转换还是必要的。

网络地址的初始化

sockaddr_in中保存的地址信息成员为32位整型值,而我们熟悉的是点分十进制(Dotted Decimal Notation)这种字符串表示方法,因此需要做相应的装换。下面介绍的一些函数将帮助我们完成这些装换

#include <arpa/inet.h>

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

int inet_aton(const char *string, struct in_addr *addr);
-> 成功时返回1(True),失败时返回0(Flase)
#include <arpa/inet.h>

char *inet_ntoa(struct in_addr addr);
-> 成功时返回转换的字符串首地址,失败时返回-

函数inet_addr和inet_aton在功能上完全相同,不过函数inet_aton可以直接返回in_addr结构体,即直接传入sockaddr_in中地址成员sin_addr的地址即可保存地址值。函数inet_ntoa则恰好与inet_aton相反,完成网络地址从32位整型值到点分十进制的字符串的转换。不过函数inet_ntoa所返回的字符串只是存储在内部临时的内存空间中,一旦下次被调用,则之前的转换字符串将被覆盖。因此,对于函数inet_ntoa的返回值我们应及时copy到自己的存储空间中。

网络地址初始化

struct sockaddr_in serv_addr;
char *serv_ip = "192.168.158.10";
char *serv_port = "";
memset(&serv_addr, , sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = inet_addr(serv_ip);
serv_addr.sin_port = htons(atoi(serv_port));

sockaddr_in地址在绑定到socket套接字时,需要先初始化并赋值。memset将sockaddr_in内存空间的所有值置0,主要是将sockaddr_in没有使用到的第4个保留参数sin_zero置0,否则可能会引起一些未知的错误(比如在与sockaddr结构体转换的过程引入的垃圾值所带来的影响)。

INADDR_ANY

之前的系列文章中提到过关于INADDR_ANY地址的思考,INADDR_ANY的作用是可以自动获取运行服务器端计算机的IP地址。若同一计算机中已分配多个IP地址(多宿主(Multi-homed)计算机,一般路由器属于这一类),则只要端口号一致,就可以从不同IP地址接收数据。因此,服务器端会优先考虑这种方式。

创建服务器端套接字为何需要配置IP地址?如上所述,同一计算机中可以分配多个IP地址,实际IP地址的个数与计算机中安装的NIC数量相等,因此,即使是服务器端也需要决定接收那个IP传来的数据。而如果服务器端只有一个NIC或服务器端根本不关心用于接收数据的IP,则可直接使用INADDR_ANY即可。

关于127.0.0.1地址

127.0.0.1是回环地址(loopback address),指的是计算机自身的IP地址。如果服务器端和客户端都运行在同一台计算机中,则使用该地址替换计算机的实际IP地址仍可正常运行。

【TCP/IP网络编程】:03地址族与数据序列的更多相关文章

  1. TCP/IP网络编程之地址族与数据序列

    分配IP地址和端口号 IP是Internet Protocol(网络协议)的简写,是为收发网络数据而分配给计算机的值.端口号并非赋予计算机的值,而是为区分程序中创建的套接字而分配给套接字的序号 网络地 ...

  2. C/C++网络编程3——地址族与数据序列

    C/C++网络编程2中介绍了套接字,这一节介绍给套接字分配ip和端口号.ip用于标识一台主机,端口号用于标识一个主机中的一个应用程序,端口号占16位,0到65535,其中0到1023是知名端口号. 表 ...

  3. 《TCP/IP网络编程》

    <TCP/IP网络编程> 基本信息 作者: (韩)尹圣雨 译者: 金国哲 丛书名: 图灵程序设计丛书 出版社:人民邮电出版社 ISBN:9787115358851 上架时间:2014-6- ...

  4. TCP/IP网络编程系列之三(初级)

    TCP/IP网络编程系列之三-地址族与数据序列 分配给套接字的IP地址和端口 IP是Internet Protocol (网络协议)的简写,是为首发网络数据而分配给计算机的值.端口号并非赋予计算机值, ...

  5. TCP/IP网络编程 读书笔记1

    本篇主干内容是TCP/IP网络编程1-9章学习笔记 1. linux文件描述符 描述符从3开始以由小到大的顺序编号,0,1,2,分配给标准I/O用作标准输入.标准输出和标准错误. 2. 协议族与套接字 ...

  6. 《TCP/IP网络编程》学习笔记整理

    简介 本笔记目前已包含 <TCP/IP网络编程>中的前 5 章,后续章节会在近期内补充完整. 我在整理笔记时所考虑的是:在笔记记完后,当我需要查找某个知识点时,不需要到书中去找,只需查看笔 ...

  7. 【网络编程】TCPIP_3_地址族与数据序列

    目录 前言 3. 地址族与数据序列 3.1 分配给套接字的 IP 地址与端口号 3.2 参数 IP 地址 3.2.1 IPV4 地址的结构体 3.2.2 地址族(Address Family) 3.2 ...

  8. TCP/IP网络编程系列之四(初级)

    TCP/IP网络编程系列之四-基于TCP的服务端/客户端 理解TCP和UDP 根据数据传输方式的不同,基于网络协议的套接字一般分为TCP和UDP套接字.因为TCP套接字是面向连接的,因此又称为基于流的 ...

  9. TCP/IP网络编程系列之二(初级)

    套接字类型与协议设置 我们先了解一下创建套接字的那个函数 int socket(int domain,int type,int protocol);成功时返回文件描述符,失败时返回-1.其中,doma ...

随机推荐

  1. Scala 学习笔记之隐式参数和隐式转换并用

    隐式转换条件: 1. 当表达式类型与预期的类型不同时 2.当对象访问一个不存在的成员时 3.当对象调用某个方法,而该方法的参数声明与传入参数不相匹时. 隐式转换搜索范围: 1. 位于源火目标类型伴生对 ...

  2. 快学Scala 第十七课 (trait 入门)

    trait 入门: trait类似于java的接口,不过比java接口功能更强大,可以有实体成员,抽象成员,实体方法,抽象方法. 如果需要混入的特质不止一个用with关键字. 带有特质的对象:(特质可 ...

  3. 在我的新书里,尝试着用股票案例讲述Python爬虫大数据可视化等知识

    我的新书,<基于股票大数据分析的Python入门实战>,预计将于2019年底在清华出版社出版. 如果大家对大数据分析有兴趣,又想学习Python,这本书是一本不错的选择.从知识体系上来看, ...

  4. Arouter核心思路和源码详解

    前言 阅读本文之前,建议读者: 对Arouter的使用有一定的了解. 对Apt技术有所了解. Arouter是一款Alibaba出品的优秀的路由框架,本文不对其进行全面的分析,只对其最重要的功能进行源 ...

  5. (图解)windows下自定义Eclipse主题

    之前用过一些编辑器如SublimeText,IDE如phpstorm,IDEA等:这些工具给我的感觉就是,除了给予这些工具应有的功能外,给予开发者更友好,更舒服的界面.Eclipse很早就开始使用了, ...

  6. RF分层封装

    1.如何管理用例? (1).在ride工具中分层管理用例(案例层.元素层.流程层),提高效率 (2).偶尔运行下,保证脚本能正常跑动 2.用例分层操作 案例层:需要加载流程层.txt资源和Seleni ...

  7. CSAPP:逆向工程【缓冲区溢出攻击】

    逆向工程[缓冲区溢出攻击] 任务描述 掌握函数调用时的栈帧结构,利用输入缓冲区的溢出漏洞,将攻击代码嵌入当前程序的栈帧中,使程序执行我们所期望的过程. 主要方法 溢出的字符将覆盖栈帧上的数据,会覆盖程 ...

  8. 22.Linux定时任务

    1.计划任务时间管理 参数 含义 -e 编辑定时任务 -l 查看定时任务 -r 删除定时任务 -u 指定其他用户 \* 表示任意的(分.时.日.月.周)时间都执行 \- 表示一个时间范围段, 如5-7 ...

  9. Mysql高手系列 - 第27篇:mysql如何确保数据不丢失的?我们借鉴这种设计思想实现热点账户高并发设计及跨库转账问题

    Mysql系列的目标是:通过这个系列从入门到全面掌握一个高级开发所需要的全部技能. 欢迎大家加我微信itsoku一起交流java.算法.数据库相关技术. 这是Mysql系列第27篇. 本篇文章我们先来 ...

  10. 音视频入门-11-PNG文件格式详解

    * 音视频入门文章目录 * PNG 文件格式解析 PNG 图像格式文件由一个 8 字节的 PNG 文件署名域和 3 个以上的后续数据块(IHDR.IDAT.IEND)组成. PNG 文件包括 8 字节 ...