本文是《Linux高级程序设计》的读书笔记,更多详细内容大家可以阅读此书
TCP/IP五层(四层)模型
- TCP/IP是一个协议簇,包含:TCP、IP、UDP、ICMP等多种协议,这些协议一起称为TCP/IP,TCP/IP将网络划分为4层模型。也有奖其划分为五层模型的,但是因为物理层我们考虑的比较少,所以通常按照四层模型来理解
网络接口层:负责数据帧的发送和接收。网络接口层将帧格式的数据放在网络上,或从网络上把帧取下来
网络层:互联协议将数据包封装成IP数据包,并运行必要的路由算法,有效的找到达到目的主机最优的路径。网络层有四种互联协议:
- 网际协议IP:负责在主机和网络之间路径寻址和路由数据包。目前主要为IPv4地址,IPv6已经在教育网中广泛使用
- 地址解析协议ARP:获得同一物理网络中的主机硬件地址
- 网际控制协议ICMP:发送消息,并报告有关数据报的传送错误
- 互联组管理协议IGMP:用来实现本地多路组播路由器报告
传输层:传输协议在主机之间提供通信会话。传输协议的选择根据数据传输方式而定。主要有以下两个传输协议:
- 传输控制协议TCP:为应用程序提供可靠的通信连接。适用于一次传输大批数据的情况,并适用于要求得到响应的应用程序
- 用户数据包协议UDP:提供了无连接通信,且不对传送包进行可靠确认。适合于依稀传输小量数据(一般小于520字节),可靠性则有应用层完成
应用层:应用程序通过这一层访问网络,主要包括常见的FTP、HTTP、DNS和TELNET协议
- TELNET:提供远程登录服务
- FTP:提供应用级的文件传输服务
- SMTP:电子邮件协议
- SNMP:简单网络管理协议
- DNS:域名解析服务,将域名映像成IP地址协议
- HTTP:超文本传输协议,Web服务器所采用的的协议
IPv4协议
在TCP/IP中,主机的MAC地址在物理上唯一的标识了一台主机;IP地址在逻辑上唯一地标识了网络中的某台主机,如果一台主机拥有多个IP地址,则在网络上有多个身份;在主机内部,传输层的端口对应唯一的应用服务。
IP地址
表示形式:主要为点分十进制表示。每个IP地址有两部分组成:网络号和主机号,对IP地址的定义如下:
struct in_addr
{
_u32 s_addr; //32bit地址
};
- 网络ID:同一个网络上所有主机使用同一个网络号,拥有相同网络主机ID并且在物理上连接的主机之间通信不需要路由设备,即他们在一个局域网内
- 主机ID:确定网络中的一个工作端、服务器、路由器或者其他TCP/IP主机。对于同一个网络号来说,主机号是唯一的。每一个主机有一个逻辑IP地址确定网络号和主机号
网段划分:
- 分为A、B、C、D、E五种类型,可以通过IP地址的前几位来确定网络地址
- 如下图示:
- A类地址:网络数为126,最后一个网段127作为本机回环测试,一个子网内允许的主机数太多;0.0.0.0~127.255.255.255
- B类地址:网络数为16384,一个子网内能允许6万5千多个主机;128.0.0.0~191.255.255.255
- C类地址:网络数为2097152,一个子网内能允许255个主机;192.0.0.0~223.255.255.255
- D类地址:被用于组播通信;224.0.0.0~239.255.255.255
- E类地址:仅供试验;249.0.0.0~247.255.255.255
在分配主机号和网络号时应遵循以下几条规则:
- 网络号不能为127。该标识号被保留作本地回路及诊断功能
- 不能将网络号和本机号个位均置为1。若置为1,则被认为是网内广播而不是一个主机号
- 各位不能均置0,否则该地被认为是本网络
- 对于本网络来说,主机号必须是唯一的
上述这种网段的划分,是由一定的局限性的,大多数组织都申请B类网络地址,导致B类地址很快被分配完了,而A类却浪费了大量的地址,在上述的划分中,A类和B类理论上一个子网可以允许大量的主机,但是在实际中,不会存在一个子网中有这么多的情况
所以我们提出一种新的划分方案CIDR——引入一个额外的子网掩码来区分网络号和主机号
子网掩码
我们针对A类这种网络主机太多的情况,提出一种重新管理网络地址的方法,A类主机太多,那么我们就通过划分子网来管理
- 子网掩码是一个32位的正整数;在子网掩码中,对应IP地址网络号的为都被置为1,所有主机号的位都被置为0
例如C类网IP地址为:192.168.0.1
对应的子网掩码为:255.255.255.0
- 网络地址可以通过IP地址和子网掩码做与运算得到
192.168.0.1 11000000 00001010 00001010 11000001
//进行与运算
255.255.255.0 11111111 11111111 11111111 00000000
//得到结果(网络号)
192.168.0.0 11000000 00001010 00001010 00000000
划分子网
根据需要划分的子网个数和被划分网络地址,可以确定子网掩码位数,一下是一个C类地址,它是根据需要划分的子网个数来确定子网掩码值:
点分十进制掩码 | 二进制子网掩码 | 子网个数 |
---|---|---|
255.255.255.0 | 11111111 11111111 11111111 00000000 | 1 |
255.255.255.128 | 11111111 11111111 11111111 10000000 | 2 |
255.255.255.192 | 11111111 11111111 11111111 11000000 | 4 |
255.255.255.224 | 11111111 11111111 11111111 11100000 | 8 |
255.255.255.240 | 11111111 11111111 11111111 11110000 | 16 |
255.255.255.248 | 11111111 11111111 11111111 11111000 | 32 |
255.255.255.252 | 11111111 11111111 11111111 11111100 | 64 |
- 我们使用255.255.255.128将C类网络192.10.10.193分成2组子网,各个子网地址、广播地址及可使用的IP地址范围如下所示:
序号 | 子网地址 | 广播地址 | 可使用IP地址范围 |
---|---|---|---|
1 | 192.10.10.1 | 192.10.10.127 | 192.10.10.2~192.10.10.126 |
2 | 192.10.10.128 | 192.10.10.255 | 192.10.10.129~192.10.10.254 |
字节顺序与大小端问题
- 小端模式:高地址存放高字节
- 大端模式:高地址存放低字节
- 在Linux系统下,如果要列出当前系统的字节顺序,可通过一下程序查看:
#include <stdio.h>
#include <endian.h>
int main(void)
{
printf(" 大端:\t%d \n 小端:\t%d \n mine: \t%d \n",__BIG_ENDIAN,__LITTLE_ENDIAN,__BYTE_ORDER);
return 0;
}
- 运行结果如下:
- 除了上述方法我们可以检测当前系统的字节顺序,还可以利用联合体来检测。联合体存放书序特点:所有成员都从低地址开始申请空间,检测代码如下:
#include <stdio.h>
#include <stdlib.h>
union word
{
int a;
char b;
}c;
//(小端) c.a 00 00 00 01 c.b 00
//(大端) c.a 01 00 00 00 c.b 01
int CheckCPU()
{
c.a = 1;
return (c.b == 1);
}
int main(void)
{
int i;
i=CheckCPU();
if(i == 0)
printf("大端\n");
else if(i == 1)
printf("小端\n");
return 0;
}
字节顺序转换函数
- 存储主机信息时,IP地址和端口号存储位网络字节顺序,所以在赋值时需要转换
- 网络字节顺序为大端,所以网络编程是同一采用大端模式
- 下面是转换函数声明:
#include <arpa/inet.h>
//n:网络字节序
//h:主机字节序
//l、s:long、short类型
uint32_t htonl(uint32_t hostlong);
uint16_t htons(uint16_t hostshort);
uint32_t ntohl(uint32_t netlong);
uint16_t ntohs(uint16_t netshort);
- 网络编程中,如果发送纯字符串给对方,则不用特殊处理
- 如果发送的是多字节数据,则必须转换为大端模式后再发送