网络应用随处可见。任何时候你浏览Web、发送E-mail 等,你就正在使用一个网络应用程序。有趣的是,所有的网络应用都是基于相同的基本编程模型,有着相似的整体逻辑结构,并且依赖相同的编程接口。
网络应用依赖于很多在系统研究中已经学习过的概念,例如,进程、信号、字节顺序、存储器映射以及动态存储分配,都扮演着重要的角色。还有一些新概念 要掌握。我们需要理解基本的客户端-服务器编程模型,以及如何编写使用因特网提供的服务的客户端-服务器程序。
每个网络应用都是基于客户端一服务器模型的。采用这个模型,一个应用是由一个服务器进程和一个或者多个客户端进程组成。服务器管理某种资源,并且通过操作这种资源来为它的客户端提供某种服务。例如,一个Web服务器管理了一组磁盘文件,它会代表客户端进行检索和执行。一个FTP服务器就管理了一组磁盘文件,它会为客户端进行存储和检索。相似地,一个电子邮件服务器管理了一些文件,它为客户端进行读和更新。
客户端-服务器模型中的基本操作是事务( transaction) 。一个客户端-服务器事务由四步组成:
1)当一个客户端需要服务时,它向服务器发送一个请求,发起一个事务。例如,当Web浏
览器需要一个文件时,它就发送一个请求给Web服务器。
2)服务器收到请求后,解释它,并以适当的方式操作它的资源。例如,当Web服务器收到
浏览器发出的请求后,它就读一个磁盘文件。
3)服务器给客户端发送一个响应,并等待下一个请求。例如, Web服务器将文件发送回客户端。
4)客户端收到响应并处理它。例如,当Web浏览器收到来自服务器的一页后,它就在屏幕
上显示此页。
注意:
我们要认识到客户端和服务器是进程,而不是常常提到的机器或者主机
,这是很重要的。一台主机可以同时运行许多不同的客户端和服务器,而且一个客户端和服务器的事务可以在同一台或是不同的主机上运行。无论客户端和服务器是怎样映射到主机上的,客户端一服务器模型是相同的。
客户端和服务器通常运行在不同的主机上,并且通过计算机网络的硬件(i/o设备)和软件资源(应用程序)来通信。
对于一个主机而言,网络只是又一种I/O设备,作为数据源和数据接收方,一个插到I/O总线扩展槽的适配器提供了到网络的物理接口。从网络上接收到的数据从适配器经过I/O和存储器总线拷贝到存储器,典型地是通过DMA (直接存储器存取方式)传送。相似地,数据也能从存储器拷贝到网络。
物理上而言,网络是一个按照地理远近组成的层次系统。
局域网(LAN):最低层的复杂程度较低的计算机网络。通常适用于一个建筑或是校园范围内。
广域网(WAN):覆盖的地理位置比局域网和城域网(覆盖城市范围的局域网)的更大,即通过路由器来将多个不兼容的局域网连接起来,组成的一个互联网(internet)。
每台路由器对于它所连接到的每个网络都有一个适配器(端口)。路由器也能连接高速点到点电话连接。
一般而言,路由器可以用来由各种局域网和广域网构建互联网络。
提出问题:
从上面我们可以看到互联网络至关重要的特性是,它能由采用完全不同和不兼容技术的各种局域网和广域网组成。每台主机和其他每台主机都是物理相连的,但是如何能够让某台源主机跨过所有这些不兼容的网络,发送数据位到另一台目的主机呢?
解决办法是一层运行在每台主机和路由器上的协议软件,它消除了不同网络之间的差异
。这个软件实现一种协议,这种协议控制主机和路由器如何协同工作来实现数据传输。这种协议必须通过统一两种机制来实现:
为主机分配地址
。互联网络协议通过定义一种一致的主机地址格式消除了这些差异。每台主机会被分配至少一个这种互联网络地址(internet address),这个地址唯一地标识了这台主机。在电缆上编码位并将这些位封装成帧的方面
,不同的联网技术有不同的和不兼容的方式。而互联网络协议通过定义一种把数据位捆扎成不连续的片(称为包)
的统一方式,从而消除了这些差异。一个包是由包头和有效载荷组成的,其中包头包括包的大小以及源主机和目的主机的地址,有效载荷包括从源主机发出的数据位。下面是一个主机和路由器如何使用互联网络协议在不兼容的局域网间传送数据的示例。这个互联网络示例由两个局域网通过一台路由器连接而成。一个客户端运行在主机A上,主机A与LAN1相连,它发送了一串数据字节到运行在主机B上的服务器端,主机B则连接在
LAN2上。这个过程包括8个基本步骤:
(1)运行在主机A.上的客户端进行了一个系统调用,从客户端的虚拟地址空间拷贝数据到内核缓冲区中。
(2)封装的主要过程:主机A上的协议软件通过在数据前附加互联网络包头和LAN1帧头,创建了一个LAN1的帧。互联网络包头寻址到互联网络主机B. LAN1帧头寻址到路由器。然后它传送此帧到适配器。注意,LAN1帧的有效载荷是一个互联网络包,而互联网络包的有效载荷是实际的用户数据。这种封装是基本的网络互联方法之一。
(3) LAN1适配器拷贝该帧到网络上。
(4)当此帧到达路由器时,路由器的LAN1适配器从电缆上读取它,并把它传送到协议
软件。
(5)路由器从互联网络包头中提取出目的互联网络地址,并用它作为路由表的索引,确定向哪里转发这个包,在本例中是LAN2。路由器剥落旧的LAN1的帧头,加上寻址到主机B的新的LAN2帧头,并把得到的帧传送到适配器。
(6)路由器的LAN2适配器拷贝该帧到网络上。
(7)当此帧到达主机B时,它的适配器从电缆上读到此帧,并将它传送到协议软件。
(8)最后,主机B上的协议软件剥落包头和帧头。当服务器进行一个读取这些数据的系统调用时,协议软件最终将得到的数据拷贝到服务器的虛拟地址空间。
注意:我们在这里主要理解互联网络里封装的概念。
OSI七层模型又叫参考模型(因为既复杂又不实用,并没有使用,只是用于理论参考)。
应用层:网络服务与最终用户的一个接口。
表示层 :数据格式转换编码,数据压缩和解压,数据加密和解密等。
会话层:允许不同主机上的用户之间,建立,管理、终止会话。
传输层:把上层数据分割成数据段,定义协议端口号,实现不同主机用户进程间的数据速信。
网络层:把上层数据封装成数据包,进行逻辑地址寻址,实现不同网络间的路径选择。
数据链路层:把上层数据封装成固定格式的帧,进行硬件地址导址,差错校验等。
物理层:物理连接,完成相邻节点之间的原始比特流的传输。
TCP/IP五层模型
TCP/IP是一组协议的代名词,它还包括许多协议,组成了TCP/IP协议簇.
TCP/IP通讯协议采用了5层的层级结构,每一层都呼叫它的下一层所提供的网络来完成自己的需求。
不同的协议层对数据包有不同的称谓,在传输层叫做段(segment),在网络层叫做数据报 (datagram),在链路层叫做帧(frame).
应用层数据通过协议栈发到网络上时,每层协议都要加上一个数据首部(header),称为封装
(Encapsulation).
首部信息中包含了一些类似于首部有多长, 载荷(payload)有多长, 上层协议是什么等信息.
数据封装成帧后发到传输介质上,到达目的主机后每层协议再剥掉相应的首部, 根据首部中的 “上层协议字段” 将数据交给对应的上层协议处理,称为分用。
每层协议数据封装的过程
数据分用过程:
IP地址
IP协议有两个版本, IPv4和IPv6. IP地址是在IP协议中, 用来标识网络中不同主机的地址;
对于IPv4来说, IP地址是一个4字节, 无符号32位的整数,
IP地址通常是以一种称为点分十进制表示法来表示的,这里,每个字节由它的十进制值表示,并且用句点和其他字节间分开。例如,128.2.194. 242就是地址0x8002c2f2的点分十进制表示。用点分割的每一个数字表示一个字节, 范围是 0 - 255;
//IP地址存放在IP地址结构中
struct in_ addr {
unsigned int s_ addr ;
};
对于IPv6来说, IP地址是一个16字节, 128位的整数,由于IPv4即将枯竭,IPV6就会代替使用。
port端口
端口是在一台主机当中标识一个进程的,类型为uint16_t, 范围:0~2^16 (0 ~ 65535)
网络当中的程序之间通信时,都是需要使用端口来通信的。
知名端口:0~1023
注册端口:从1024 到49151
常见进程默认端口mysql -> 3306 ; oracle -> 1521
MAC地址
MAC地址用来识别数据链路层中相连的节点;长度为48位, 及6个字节. 一般用16进制数字加上冒号的形式来表示(例如: 08:00:27:03:fb:19),在网卡出厂时就确定了, 不能修改。
mac地址通常是唯一的(虚拟机中的mac地址不是真实的mac地址, 可能会冲突; 也有些网卡支持用户配置mac地址).
字节序: CPU对内存当中的数据进行存取的顺序
大端字节序:低地址存高位
小端字节序:低地址存低位
网络字节序为大端字节序:在ip地址结构中存放的地址总是以大端字节序顺序存放的,即使主机字节序是小端字节序,也可以通过函数在网络和主机字节直接转换。
#include
uint32_t htonl(uint32_t hostlog) //将32位的主机字节序转换为网络字节序,引申含义:小端字节序转换为大端字节序,而大端字节序不需要进行转换
uint32_t ntohl(uint32 _t netlog) //将32位的网络字节序转换为主机字节序;
uint16_t htons(uint16_t hostshort) //将16位的主机字节序转换为网络字节序
uint16_t ntohs(uint16_t netshort) //将16位的网络字节序转换为主机字节序
IP地址和点分十进制串之间的转换
可以使用inet_aton 和inet_ntoa函数来实现:
#include
int inet_aton(const char *cp, struct in_addr *inp) ;
inet_aton 函数将-一个点分十进制串(cp)转换为一个网络字节顺序的IP地址(inp)。
返回:若成功则为1,若出错则为0。
char *inet_ntoa(struct in_addr in) ;
inet_ntoa函数将一个网络字节顺序的IP地址转换为它所对应的点分十进制串。
返回:指向点分十进制字符串的指针。
//“n”表示的是网络(network)。 “a”表示应用( application)。而“to"表示转换。
注意:
对inet_ aton的调用传递的是指向结构的指针,而对inet_ntoa的调用传递的是结构本身。