OSI参考模型是由国际标准化组织ISO提出的网络采用分而治之的方法设计,将网络的功能划分为不同的模块,以分层的形式有机组合在一起。每层实现不同的功能,其内部实现方法对外部其他层次来说是透明的。每层向上层提供服务,同时使用下层提供的服务。
网络体系结构即指网络的层次结构和每层所使用协议的集合。
层次结构(从下往上说):物数网传会表应。
注:OSI模型是一个理想化的模型,尚未有完整的实现。但是OSI模型本身是有意义的,因为其他的模型都是参考着这个模型而来的。
TCP/IP协议族中有很多个协议,不仅仅只有TCP和IP两个协议。
TCP/IP协议是Internet事实上的工业标准。一共有四层(从下往上说):网络接口和物理层,网络层,传输层,应用层。
TCP/IP协议族每层常见的协议:
应用层:HTTP(Hypertext Transfer Protocol) 超文本传输协议
万维网的数据通信的基础
FTP(File Transfer Protocol) 文件传输协议
是用于在网络上进行文件传输的一套标准协议,使用TCP传输
TFTP(Trivial File Transfer Protocol) 简单文件传输协议
是用于在网络上进行文件传输的一套标准协议,使用TCP传输
SMTP(Simple Mail Transfer Protocol) 简单邮件传输协议
一种提供可靠且有效的电子邮件传输的协议
传输层:TCP(Transport Control Protocol) 传输控制协议
是一种面向连接的、可靠的、基于字节流的传输层通信协议
UDP(User Datagram Protocol) 用户数据报协议
是一种无连接、不可靠、快速传输的传输层通信协议
网络层:IP(Internetworking Protocol) 网际互连协议
是指能够在多个不同网络间实现信息传输的协议
ICMP(Internet Control Message Protocol) 互联网控制信息协议
用于在IP主机、路由器之间传递控制消息----ping命令
IGMP(Internet Group Management Protocol) 互联网组管理
是一个组播协议,用于主机和组播路由器之间通信
链路层:ARP(Address Resolution Protocol) 地址解析协议
通过IP地址获取对方mac地址
RARP(Reverse Address Resolution Protocol) 逆向地址解析协议
通过mac地址获取对方ip地址
注意:每一层使用的协议由下层使用的协议决定,不能乱用。每层不一定只能使用一个协议。
对于数据包的封装和拆分过程,如果每层的协议,及协议的详细信息都由应用层程序员来处理的话,那有点太不友好了,且程序员的操作出错的概率还比较大。所以linux内核封装了各种协议栈,用户使用哪个协议,只需要调用系统提供的系统调用接口函数,传递对应的参数即可,剩下的封装协议的过程,由linux内核来完成。------拆分的过程同理。
插一句:内核程序的五大功能:
1.文件管理:将一堆 0 和 1 转换成我们人类好识别的字符
2.进程管理:负责进程调度机制的,时间片轮转、上下文切换
3.设备管理:linux下一切皆文件
4.网络管理:网络协议栈
5.内存管理:如栈上分配的空间由操作系统负责回收
不同类型CPU的主机中,内存存储多字节整数序列有两种方法,称为主机字节序(HBO):
小端序(little-endian): 低序字节存储在低地址,将低字节存储在起始地址,称为“Little-Endian”字节序,Intel、AMD等采用的是这种方式;
大端序(big-endian)- 高序字节存储在低地址,将高字节存储在起始地址,称为“Big-Endian”字节序,由ARM、Motorola等所采用这种方式。
因为不同主机的字节序可能不同,所以收发的数据单位一旦超过一个字节,就可能出现发送端和接收端解析到的不一样的情况,如发送端是小端存储发送的是 0x1234,接收端是大端存储,会被解析成0x3412,这样就有问题了。所以网络字节序,规定为大端序,如果数据想要在网络中发送,必须转换成大端字节序发送,接收者接收到的就是大端字节序,然后接受者可以根据自己主机的字节序在决定如何将从网络上接到的数据进行解析。
什么时候需要考虑字节序的问题:
1.如果能明确知道发送端和接收端主机字节序是一样的,可以不同考虑。
2.对于字符串,也无需考虑字节序问题 ,如"12345678",1一定是在地址低位。
当发送的数据单位超过1个字节,就需要考虑字节序的问题了。
如何判断自己的主机是大端存储还是小端存储:
#include
//或者使用 共用体也可以 union
int main(){
int a = 0x12345678;
char *p = (char *)&a;
if(*p == 0x78){
printf("小端\n");
}else if(*p == 0x12){
printf("大端\n");
}
return 0;
}
网络字节序和主机字节序转换的函数:
h:host 主机 n:net 网络
主机字节序到网络字节序 u_long htonl(u_long hostlong);
u_short htons(u_short short);
网络字节序到主机字节序 u_long ntohl(u_long hostlong);
u_short ntohs(u_short short);
示例:
#include
#include
int main(){
unsigned int value = 0x12345678;
unsigned int ret = htonl(value);
printf("value = %#x\n", value);
printf("ret = %#x\n", ret);
return 0;
}
socket本身也是用来做同主机不同进程通信的,有了TCP/IP协议族的加入,才能做不同主机之间的通信。
socket是一个编程接口,是一种特殊的文件描述符 (everything in Unix is a file),并不仅限于TCP/IP协议。(TCP--面向连接,UDP--无连接)
socket作用:使用socket,能将复杂的网络通信过程简化成普通的I/O操作过程 (打开文件->读/写操作->关闭文件)引入了新型的“I/O”操作。且TCP/IP协议族被集成到操作系统的内核中,程序员只需要给函数出参就能指定要封装的协议了。
socket类型:
①流式套接字(SOCK_STREAM):提供了一个面向连接、可靠的数据传输服务,数据无差错、无重复的发送且按发送顺序接收。内设置流量控制,避免数据流淹没慢的接收方。数据被看作是字节流,无长度限制。
②数据报套接字(SOCK_DGRAM):提供无连接服务。数据包以独立数据包的形式被发送,不提供无差错保证,数据可能丢失或重复,顺序发送,可能乱序接收。
③原始套接字(SOCK_RAW):可以对较低层次协议如IP、ICMP直接访问。
①IP地址和MAC地址的区别:局域网内部通信使用的是MAC地址。如果数据想要走出局域网,就要使用IP地址了。
MAC地址长度:6个字节
IP地址又分为 IPV4 和 IPV6,因为IPV4地址不够用了,所以才出现的IPV6,但是现在有很多方法能暂时解决IPV4不够用的问题,如NAT技术可以将局域网IP替换成公网IP,所以,企业目前还是使用IPV4居多,如果后面企业要求使用IPV6了,自己去查一下IPV6地址的处理方式即可。
IPV4地址长度:4字节 32bit
IPV6地址长度:16字节 128bit
通过百度查到的IP地址:是公网IP地址,是在运营商付费租过来的。
通过ifconfig/ipconfig 查到的IP地址:是局域网IP地址,如果不向外发送数据,是免费的。
②IPV4地址分类:
网络号 |
主机号 |
规定最高位 |
范围 |
使用单位 |
|
---|---|---|---|---|---|
A | 1字节 |
3字节 |
0 |
0.0.0.0 - 127.255.255.255 |
政府/大公司/学校 |
B | 2字节 |
2字节 |
10 | 128.0.0.0-191.255.255.255 |
中等规模的公司 |
C | 3字节 |
1字节 |
110 | 192.0.0.0-223.255.255.255 |
个人 |
D | 1110 |
224.0.0.0-239.255.255.255 | 组播 |
||
E | 11110 |
240.0.0.0-255.255.255.255 | 保留测试用的 |
其中每个IP地址又可以通过路由器,下发局域网IP地址,每类IP地址都有专门划分子网的保留段。
③子网掩码:是由一堆连续的1和连续的0组成的。用来和IP地址取与运算来获取网络号的。从而能限制某一网段内能容纳的最大主机数。
如,ip地址是192.168.70.8 子网掩码设置成 255.255.255.0取与运算可以得到的结果:192.168.70.0 ----这是网络号,网络号相同时,才能进行通信。该网段内共有IP地址 256 个:
其中 192.168.70.0 是网络号,是不能占用的
192.168.70.255 是广播的地址,也不能占用
网关设备也需要占用一个IP地址,一般是同一局域网内可用的编号最小的。(192.168.70.1)
所以能容纳的主机数:256-1-1-1(网关设备也可以算作一台IP主机) = 254
问:192.168.70.x 网段将子网掩码设置成 255.255.255.128,同一子网能容纳的最大主机数?
答案:这种方式可以将同一网段再划分成两个子网
第一个子网IP地址范围:192.168.70.0~192.168.70.127
第二个子网IP地址范围:192.168.70.128~192.168.70.255
其中每个子网中有需要减掉 网络号 广播地址 网关地址
所以子网掩码不一定都是255255255.0 网关设备的IP地址也不一定是编号最小的。
④IP地址的表示方式:"192.168.70.8" 叫做点分十进制,是一个字符串,是给人看的。
注:在计算机中他就是一个 无符号的4字节的整型。IP地址是4字节的,所以再内存上存储需要考虑大小端的问题。
⑤ip地址转换需要用到的函数:
inet_addr()
功能:将点分十进制的字符串的ip地址转换成网络字节序无符号整型
函数原型:in_addr_t inet_addr(const char *strptr);
inet_ntoa()
功能:将32位网络字节序二进制地址转换成点分十进制的字符串。
函数原型:char *inet_ntoa(stuct in_addr inaddr);
示例:
#include
#include
#include
#include
int main(){
char ip[32] = "192.168.70.8";
//ret_ip 存储的是 网络字节序的无符号整型的ip
unsigned int ret_ip = inet_addr(ip);
unsigned char *p = (unsigned char *)&ret_ip;
//192.168.70.8
printf("%d.%d.%d.%d\n", *p, *(p+1), *(p+2), *(p+3));
return 0;
}
进程号在linux系统中,可以用来唯一标识进程,但是进程号是由操作系统来管理的,进程停止再次启动后,进程号一般就会发生变化。所以就发明了端口号,端口号可以人为的指定标识某个进程,这样,才能保证数据到达指定主机的指定进程。
端口号一般由IANA (Internet Assigned Numbers Authority) 管理,端口号最大值是65535。
众所周知端口:1~1023(1~255之间为众所周知端口,256~1023端口通常由系统占用)
已登记端口:1024~49151
动态或私有端口:49152~65535
使用 unsigned short 存储,需要考虑字节序!
常见服务对应的端口号:
ssh 22
telnet 23
tftp 69
ftp 21
http 80 8080
https 443
我们使用端口号时,使用 8888 9999 6789 ..
注:可以在 /etc/services 文件中查看系统中已经被占用的端口号。.
以ubuntu作为客户端,以win的网络调试助手作为服务器,收发几个包测试。
数据帧的大小:46-1500
有的书上写的是:64-1518 ,区别就是包不包含以太网头和以太网尾
系统中有一个值叫 MTU,MTU叫做最大传输单元。
目的地址:目的MAC地址
源地址:源MAC地址
类型:后面使用的协议的类型
0800 IP协议
0806 ARP协议
8035 RARP协议
版本:IP协议的版本 4 使用的ipv4
首部长度:IP头长度,注意此处使用的是4倍的单位,1-->4 5-->20
总长度:指首部加上数据的总长度,单位为字节
生存时间TTL:表明是数据报在网络中的寿命,即为“跳数限制”,由发出数据报的源点设置这个字段。路由器在转发数据之前就把TTL值减一,当TTL值减为零时,就丢弃这个数据报。
通常设置为32、64、128
协议类型:后面使用的协议的类型 ICMP(1),IGMP(2),TCP(6),UDP(17)
源IP地址:Ubuntu的IP地址
目的IP地址:WIN的IP地址
TCP报头:
UDP报头:
源端口号:Ubuntu的端口号
目的端口号:Win的端口号
头部长度:4倍的单位 5--->20
三次握手是发生在tcp的客户端和服务器建立连接的过程中的客户端的connect函数 和 服务器的 listen accept 函数之间。
三次握手主要为了确认通信的双方收发数据的能力都没问题。
四次挥手是发生在通信的双方有一方关闭套接字或者退出时发生的。即使退出了,也会完成四次挥手。 ----atexit()
四次挥手主要是确保数据都传输完毕了双方才能退出。