登 录
注 册
< 系统运维
Linux
计算机系统
系统工具
系统硬件组成
高速缓存
存储器及操作系统
Amdahl定理
信息表示和处理
内存有关错误
全球IP因特网
信号量同步线程
热门推荐>>>
中台架构
中台建设与架构
Hadoop
源码分析-NN启动(三)
HBase
HBased对接Hive
Linux
Nginx高可用
Python
数据导出工具
Flink
3分钟搭建Flink SQL测试环境
Kafka
Kafka对接Flume
深度学习
卷积神经网络
数据结构与算法
选择合适的算法
MySQL
数据备份恢复
Hive
Hive调优参数大全
其他框架
Azkaban Flow1.0与2.0
ClickHouse
表引擎-其他类型
技术成长
最好的职业建议
精选书单
技术成长书单—机器学习
技术资讯
数据在线:计算将成为公共服务
开发工具
IntelliJ IDEA 20年发展回顾(二)
系统工具
Mac命令行工具
虚拟化
内存虚拟化概述
云原生
云原生构建现代化应用
云服务
一文搞懂公有云、私有云...
Java
Spring Boot依赖注入与Runners
Go
Go函数与方法
SQL
SQL模板
安全常识
一文读懂SSO
当前位置:
首页
>>
计算机系统
>>
全球IP因特网
全球IP因特网
2020-07-05 14:03:55 星期日 阅读:2143
![](/static/images/article_images/1693753453.99138.jpeg) 全球IP因特网是最著名和最成功的互联网络实现。从1969年起,它就以这样或那样的形式存在了。虽然因特网的内部体系结构复杂而且不断变化,但是自从20世纪80年代早期以来,客户端-服务器应用的组织就一直保持这相当的稳定。 每台因特网主机都运行实现`TCP/IP协议的软件`(Transmission Control Protocol/Internet Protocol,传输控制协议/互联网络协议)。几乎每个现代计算机系统都支持这个协议。因特网的客户端和服务器混合使用套接字接口函数和Unix I/O函数来进行通信(我们将在第11.4节中介绍套接字接口)。通常将套接字函数实现为系统调用,这些系统调用会陷入内核,并调用各种内核模式的TCP/IP函数。 TCP/IP实际是一个协议族,其中每一个都提供不同的功能。例如,IP协议提供基本的命名方法和传递机制,这种传递机制能够从一台因特网主机往其他主机发送包,也叫做数据报(datagram)。IP机制从某种意义上而言是不可靠的,因为,如果数据报在网络中丢失或者重复,它并不会试图恢复。`UDP(Unreliable Datagram Protocol,不可靠数据报协议)`稍微扩展了IP协议,这样一来,包可以在进程之间而不是在主机之间传送。TCP是一个构建在IP之上的复杂的协议,提供了进程间可靠的全双工(双向)连接。为了简化讨论,我们将TCP/IP看作是一个单独的整体协议。我们将不讨论它的内部工作,只讨论TCP和IP为应用程序提供的某些基本功能。我们将不讨论UDP。 从程序员的角度,我们可以把因特网看做一个世界范围的主机集合,满足以下特性: `主机集合被映射为一组32位的IP地址;` `这组IP地址被映射为一组称为因特网域名(Internet domain name)的标识符;` `因特网主机上的进程能够通过连接(connection)和任何其他因特网主机上的进程通信。` ####关于IPv4和IPv6 最初的因特网协议,使用32位地址,称为因特网协议版本4(Internet Protocol Version 4,IPv4)。1996年,因特网工程任务组织提出了一个新版本的IP,称为因特网协议版本6(Internet Protocol Version 6,IPv6),它使用的是128位地址,意在替代IPv4。但是直到2015年,大约20年后,因特网流量的绝大部分还是由IPv4网络承载的。例如,只有4%的访问Google服务的用户使用IPv6。 ####IP地址 一个IP地址就是一个32位无符号整数。网络程序将IP地址存放在如下代码所示的IP地址结构中。 ``` /* IP address structure */ struct in_addr { uint32_t s_addr; /* Address in network byte order (big-endian) */ } ``` 把一个标量地址存放在结构中,是套接字接口早期实现的不幸产物。为IP地址定义一个标量类型应该更有意义,但是现在更改已经太迟了,因为已经有大量应用是基于此的。 因为因特网主机可以有不同的主机字节顺序,TCP/IP为任意整数数据项定义了统一的网络字节顺序(network byte order)(大端字节顺序),它放在包头中跨过网络被携带。在IP地址结构中存放的地址总是以(大端法)网络字节顺序存放的,即使主机字节顺序(host byte order)是小端法。Unix提供了下面这样的函数在网络和主机字节顺序间实现转换。 ``` #include <arpa/inet.h> uint32_t htonl(uint32_t hostlong); uint16_t htons(uint16_t hostshort); // 返回:按照网络字节顺序的值 uint32_t ntohl(uint32_t netlong); uint16_t ntohs(uint16_t netshort); // 返回:按照主机字节顺序的值 ``` hotnl函数将32位整数由主机字节顺序转换为网络字节顺序。ntohl函数将32位整数从网络字节顺序转换为主机字节。htons和ntons函数为16位无符号整数执行相应的转换,注意,没有对应的处理64位值的函数。 IP地址通常是以一种称为点分十进制表示法来表示的,这里,每个字节由它的十进制值表示,并且用句点和其他字节间分开。例如,128.2.194.242就是地址0x8002c2f2的点分十进制表示。在Linux系统上,你能够使用HOSTNAME命令来确定你自己主机的点分十进制地址。 ``` linux> hostname -i 128.2.194.242 ``` 应用程序使用inet_pton和inet_ntop函数来实现IP地址和点分十进制串之间的转换。 ``` #include <arpa/inet.h> int inet_pton(AF_INET, const char *src, void *dst); // 返回:若成功,则为1,若src为非法点分十进制地址则为0,若出错则为-1) const char *inet_ntop(AF_INET, const void *src, char *dst, socklen_t size); // 返回: 若成功则为指向点分十进制字符串的指针,若出错则为NULL ``` inet_pton函数将一个点分十进制串(src)转换为一个二进制的网络字节顺序的IP地址(dst)。如果src没有指向一个合法的点分十进制字符串,那么该函数就会返回0。任何其他错误会返回-1,并设置errno。相似地,inet_ntop函数将一个二进制的网络字节顺序的IP地址(src)转换为它所对应的点分十进制表示,并把得到的以null结尾的字符串的最多size个字节复制到dst。 ####因特网域名 因特网客户端和服务器相互通信时使用的是IP地址,然而,对于人们而言,大整数是很难记住的,所以,因特网也定义了一组更加人性化的域名(domain name),以及一种将域名映射到IP地址的机制。域名是一串用句点分隔的单词(字母、数字和破折号),例如,whaleshark.ics.cs.cmu.edu。 域名集合形成了一个层次结构,每个域名编码了它在这个层次中的位置。通过一个示例让你将很容易理解这点。下图展示了域名层次结构的一部分。层次结构可以表示为一棵树。树的节点表示域名,反向到根的路径形成了域名。子树称为子域(subdomain)。层次结构中的第一层是一个未命名的根节点。下一层是一组一级域名(first-level domain name),由非营利组织ICANN(Internet Corporation for Assigned Names and Numbers,因特网分配名字数字协会)定义。常见的第一层域名包括com、edu、gov、org和net。 ![](https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=2985146673,1414780200&fm=26&gp=0.jpg) 下一层是二级域名(second-level),例如,cmu.edu,这些域名是由ICANN的各个授权代理按照先到先服务的基础分配的。一旦一个组织得到了一个二级域名,那么它就可以在这个子域中创建任何新的域名了。例如,cs.cmu.edu。再比如,百度得到了baidu.com的域名,那么它就可以在baidu.com前面加任何域名了,如:map.baidu.com、news.baidu.com等等。 因特网定义了域名集合和IP地址集合之间的映射。直到1988年,这个映射都是通过一个叫做HOSTS.TXT的文本文件来手工维护的。从那以后,这个映射是通过分布世界范围内的数据库(称为DNS(Domain Name System,域名系统))来维护的。从概念上而言,DNS数据库由上百万的主机条目结构(host entry structure)组成,其中每条定义了一组域名和一组IP地址之间的映射。从数学意义上讲,可以认为每条主机条目就是一个域名和IP地址的等价类。我们可以用Linux的NSLOOKUP程序来研究DNS映射的一些属性,这个程序能展示与某个IP地址对应的域名。 每台因特网主机都有本地定义的域名localhost,这个域名总是映射为回送地址(lookback address)127.0.0.1 ``` 22:41[shenlibin@slbdembp|~/Desktop]$ nslookup localhost Server: 192.168.1.1 Address: 192.168.1.1#53 Name: localhost Address: 127.0.0.1 ``` localhost名字为引用运行在同一台机器上的客户端和服务器提供了一种便利和可移植的方式,这对调试相当有用。我们可以使用HOSTNAME来确定本地主机的实际域名。在最简单的情况中,一个域名和一个IP地址之间是一一映射。然而,在某些情况下,多个域名可以映射为同一个IP地址,在最通常的情况下,多个域名可以映射到同一组的多个IP地址。 ``` linux> nslookup www.twitter.com Address:199.16.156.6 Address:199.16.156.70 Address:199.16.156.102 Address:199.16.156.230 linux>nslookup twitter.com Address:199.16.156.102 Address:199.16.156.230 Address:199.16.156.6 Address:199.16.156.70 ``` 最后,我们注意到某些合法的域名没有映射到任何IP地址: ``` 23:20[shenlibin@slbdembp|~/Desktop]$ nslookup edu Server: 192.168.1.1 Address: 192.168.1.1#53 Non-authoritative answer: *** Can"t find edu: No answer 23:21[shenlibin@slbdembp|~/Desktop]$ ``` ####因特网连接 因特网客户端和服务器通过在连接上发送和接收字节流来通信。从连接一对进程的意义上而言,连接是点对点的。从数据可以同时双向流动的角度来说,它是全双工的。并且从(除了一些如粗心的耕锄机操作员切断了电缆引起灾难性的失败以外)由源进程出发的字节流最终被目的进程以它发出的顺序收到它的角度来说,它也是可靠的。 一个套接字是连接的一个端点。每个套接字都有相应的套接字地址,是由一个因特网地址和一个16位的整数端口组成的。用“地址:端口”来表示。 当客户端发起一个连接请求时,客户端套接字地址中的端口是由内核自动分配的,称为临时端口。然而,服务器套接字地址中的端口通常是某个知名端口,是个这个服务相对应的。例如,Web服务器通常使用端口80,而电子邮件服务器使用端口25。每个具有知名端口的服务都有一个对应的知名的服务名。例如,Web服务的知名名字是http,email的知名名字是smtp。文件/etc/services包含一张这台机器提供的知名名字和知名端口之间的映射。 一个连接是由它两端的套接字地址唯一确定的。这对套接字地址叫做套接字对(socket pair),由下列元组来表示: (cliaddr:cliport, servaddr:servport) 其中cliaddr是客户端的IP地址,cliport是客户端的端口,servaddr是服务器的IP地址,servport是服务器的端口。例如,图11-11展示了一个Web客户端和一个Web服务器之间的连接。 在这个示例中,Web客户端的套接字地址是: 128.2.194.242:51213 其中端口号51213是内核分配的临时端口号。Web服务器的套接字地址是: 208.216.181.15:80 其中端口号80是和Web服务器相关联的知名端口号。给定这些客户端和服务器套接字地址,客户端和服务器之间的连接就由下列套接字对唯一确定了。 (128.2.194.242:51213, 208.216.181.15:80) ####因特网的起源 因特网是政府、学校和工业界合作的最成功的示例之一。它成功的因素很多,但是我们认为有两点尤其重要: 美国政府30年持续不变的投资; 充满激情的研究人员对麻省理工学院的Dave Clarke提出的“粗略一致和能用的代码”的投入。