admin 管理员组文章数量: 887018
六十四、网络编程基础
1. 网络基础
1.1 网络编程的概念
- 网络编程就是进程间通信,只不过多个进程间不一定在同一台主机上。
- 由于不在同一个主机上,不在同一个进程上就需要注意协议。
1.2 联网协议和层
- 联网协议:定义如何在一个网络上传输信息的一组规则
1.2.1 网络采用分层的思想
- 在计算机网络体系中,采用层次化的思想,将通信协议中必要的功能进行分层。
- 每一层都接收由它下一层所提供的特定服务,并且负责为自己的上一层提供特定的服务。
- 上下层之间进行交互所遵循的约定叫做『接口』。
- 同一层之间进行交互所遵循的约定叫做『协议』。
- 『接口』 即相邻两层之间交换位置的连接点,是上层使用下层服务的入口。
- 『协议』 即通信双方所做的一些约定,比如怎么开始通信、信息的格式与顺序、怎么结束通信等。
- 分层的好处:
- 各层之间独立,每一层不需要知道下一层如何实现,而仅仅只需要知道该层通过层间的接口所提供的的服务。
- 稳定,当任何一层发生变化时,只要层间接口关系保持不变,则这层以上或以下层不受影响。
- 易于实现和维护(知道是什么功能,就到指定层去查找)
- 促进标准化工作
1.2.2 OSI体系结构(重点!!)
- ISO(国际标准化组织)制定了一个国际标准OSI(开放式通讯系统互联参考模型),对通讯系统进行了标准化。
- 定义了7层模型
顺口溜:(虽然貌似有点不顺)
屋里(物理)数据要跑路,沿着链路上高速。—>物理层,数据链路层
跑到高速没网络,数据传输靠不住。—>网络层,传输层
掏出手机要叫人,一开会话嘟嘟嘟。—>会话层
老铁表示要玩完,应用技术才懂路。—>表示层、应用层
1.2.3 TCP/IP协议介绍
- OSI模型是一个理想化的模型已经很少使用,没有完整的实现,但是模型本身非常通用。
- TCP/IP协议 是Internet事实上的工业标准
(1) 网络接口与物理层 也叫做网络访问层
- 功能:包括ip地址与物理地址的映射(MAC),以及将上一层的ip报文封装层帧,转换成二进制比特流传输
- MAC:物理地址,48bit全球唯一,网卡编号,网络设备的身份标识(cmd —>ipconfig/all),由厂商出厂后确定。
- 改变网络环境后,IP地址变,MAC地址不变
- 由电气电子工程协会IEEE定义。
部分协议举例:
- ARP/RARP 地址解析协议/逆向地址解析协议
- ARP(Address Resolution Protocol):通过ip地址获取其对应的mac地址。
- RARP(Reverse Address Resolution Protocol):通过mac地址获取其对应的ip地址。
- PPP(Point to Point Protocol)协议:拨号协议(GPRS/3G/4G)
MTU:最大传输单元:1500bytes
MSS:最大报文长度:1460bytes
(2) 网络层
- 负责在主机之间的通讯中选择数据包传输的路径,即选择路由。
① IP协议(Internet Protocol)
- ip协议根据数据包的目的ip地址来决定如何投递数据包。
- 如果数据包不能直接投递给目标主机,那么ip协议就为他寻找下一个合适的下一跳路由器。
- 路由器就是工作在网络层
② ICMP协议(Internet Control Management Protocol)
- 英特网控制管理协议,ping检测网络就是用这个协议
- 用于在IP主机、路由器之间传递控制消息
- ping 命令 使用的就是这个协议
③ IGMP协议(Internet Group Management Protocol)
- 英特网分组管理协议,组播,广播。
(3) 传输层(重点!)
- 负责提供应用程序之间通讯服务,这种服务又称之为端到端。
- 传输层与网络层不同,传输层只关心通讯的 起始端 和 目的端,并不在乎数据包的传输中转过程。
- TCP :(transmission control Protocol 传输控制协议):提供面向连接的,一对一的可靠数据传输协议。
- UDP :(user datagram Protocol 用户数据报协议):提供无连接的,不可靠的尽力的传输协议,但是效率更高
(4) 应用层
- 负责处理应用程序的逻辑
① HTTP/HTTPS
超文本传输协议,万维网数据通信的基础
http:明文发送, https加密传输
② 邮件协议
收: POP3(post office protocol)邮局协议第三个版本
从服务器接收右键,接收完后服务器就没有这个邮件了;
发: SMTP(简单邮件传输协议)
IMAP: 交互式邮件存储协议,与POP3类似的邮件访问标准协议之一。
收取邮件后,服务器上邮件依然存在,如果删除、标记服务器也会做相应操作。
③ FTP(FILE Transfer Protocol)
文件传输协议,是用于在网络上进行文件传输的一套标准协议,使用TCP传输
④ TFTP
简单文件传输协议,适用于在网络上进行文件传输的一套标准协议,使用UDP传输
⑤ DNS
Telnet/ssh :远程登录
1.2.4 网络封包与拆包
MTU :
- Maximum Transmission Unit 最大传输单元
- 物理接口(数据链路层)提供给上层(网络层(IP层))最大一次传输数据的大小。
- 规定了数据链路层所能传送最大数据长度
- 以太网为例,缺省MTU=1500字节,这是以太网接口对IP层的约束
- 如果IP层<=1500字节需要发送,只需要一个IP包就可以
- 如果IP层>1500字节需要发送,需要分片才能发送(分片:帧)
MSS:
- Maximum Segment Size 最大报文长度
- TCP提交给IP层最大分段大小,指TCP报文所允许传送数据部分最大长度。
- 不包含TCP头,MSS式TCP来限制应用层最大发送字节数。
- 如果MTU=1500,则MSS = 1500-20(IP header)-20(TCP header) =1460字节
- 如果应用有2000字节要发,需要2 Segment
- 第一个TCP Segment = 1460 第二个TCP Segment = 540
1.3 TCP和UDP协议的异同点(重点!!!)
- 相同点: 都属于传输层协议
- 不同点:
- TCP
1. 是提供面向连接的,可靠的稳定的数据传输协议。
2. 数据在传输过程中,无误,无丢失,无失序,无重复到达的通信。
1.1 每一个数据包都会编上一个编号,该编号称之为序列号(seq),且每一个数据包都需要一个正确的应答包应答
1.2 应答包:应答数据包,且通知对方下一次从哪个包开始发送(应答号:ack)。
3. 超时重传机制。
3. 传输效率低,耗费资源多。
4. 在数据链路层限制数据包大小(46~1500bytes),超出部分分帧发送。
5. 数据的收发是不同步的,会粘包(不存在数据边界)
5.1 粘包:为了提高效率,将多个足够小,且发送间隔极短的数据包合成一个包发送,该现象称之为粘包现象,该算法称之为Nagle算法。
适用场景: 适用于对传输质量要求比较高,传输大量数据的通信,在需要可靠数据传输的场合,通常使用TCP协议。
例如: 网上购物付钱的时候,装备购买,账户密码登录的时候
- UDP
1.是提供无连接的,不可靠的尽力的数据传输协议。
2.数据在传输过程中有可能出现,错误,丢失,失序,重复到达的通信。
3. 传输效率高
4. 限制每次传输的大小(46~1500bytes),超出部分直接删除。
5. 数据收发是同步的,不存在粘包现象(存在数据边界)
适用场景: 适用于对传输质量要求比较低,传输小尺寸数据的通信,给出应答比较困难的网络中使用。
例如: 广播/组播 直播 语音视频电话,多人竞技类游戏。
1.4 IP地址
- IP地址是因特网中主机的标识,每个数据包都必须携带目的IP地址和源IP地址,路由器依靠此信息为数据包选择路由。
- IP地址是路由器下发的。(自动,手动)
1.4.1 IP地址的分类
1. IPv4:占4个字节,采用32bit的无符号整数来存储IP地址。[0, 2^32-1],给你个2^32个 = 42.9亿
1.1 局域网:为了解决IP地址不够用的问题,让多台主机使用同一个广域网IP地址。
1.2 广域网:与外界通信的网络环境。
1.3 每一个IP地址都可以下发一个局域网。
2. IPv6:占16个字节,采用128bit的无符号整数来存储IP地址。[0, 2^128-1];
2.1 容量足够多,能够给地球上的每一粒沙子都分配一个IP地址。
2.2 IPv4往IPv6过渡的阶段还未完成。IPv4和IPv6尚不兼容。
桥接模式和net模式的区别?
桥接模式:windows和ubuntu是兄弟关系,连接同一个路由器
net模式:windows当做路由器,下发一个网络给ubuntu
1.4.2 IP地址划分
-
由于IP地址基数比较大,所以为了提高寻径效率,则将IP地址划分成二级IP地址;
- 二级IP地址 = 网络号 + 主机号
- 网络号: 确定计算机从属的物理网络地址(确定是哪个村子的)
- 主机号: 确定网络号后,用主机号标识该网络号中的所有主机。(确定是哪个村子后,在村子中找到设备的编号)
注意:
- ABC类为基本类,可以分配给主机使用,且只有ABC类可以分配给主机使用
- D类:不表示网络,用于特殊用途:组播,多播组
- E类:保留,或者实验室使用。
1.4.3 点分十进制
- 使用点分十进制是为了方便记忆。
- 将32位IP地址的二进制数,以8bit为一组,用十进制表示,利用点分割
IP地址范围 | 网络号个数 | 主机号个数 | ||
---|---|---|---|---|
A类地址 | 0.0.0.0~127.255.255.255 | 2^7(网络号) | 2^24(主机号) | 大型网络 |
B类地址 | 128.0.0.0~191.255.255.255 | 2^14 | 2^16 | 名地址网管中心 |
C类地址 | 192.0.0.0~223.255.255.255 | 2^21 | 2^8 | 校园网或企业网、家庭网 |
D类地址 | 224.0.0.0~239.255.255.255 | 组播地址 | ||
E类地址 | 240.0.0.0~255.255.255.255 | 保留 |
在ABC类中的特殊IP地址:不能分配给主机使用。(掐头去尾)
- 网络地址:代表该网络的。由有效网络号 + 全是0的主机号组成
如:
110.1.2.3 —> A类IP地址 —>网络号是前8bit —>110.0.0.0
129.1.2.3 —> B类IP地址 —>网络号是前16bit —>129.1.0.0
200.1.2.3 —> C类IP地址 —>网络号是前24bit —>200.1.2.0 - 广播地址:向该IP地址发送,代表给当前网络下的所有主机发送数据。由有效网络号 + 全是1的主机号组成
如:
110.1.2.3 —> A类IP地址 —> 网络号是前8bit —> 110.255.255.255
129.1.2.3 —> B类IP地址 —> 网络号是前16bit —> 129.1.255.255
200.1.2.3 —> C类IP地址 —> 网络号是前24bit —> 200.1.2.255
1.4.4 子网掩码(重点!)
- 二级IP地址划分后,主机的基数还是比较大,所以引入了另外一个概念:子网掩码。利用子网掩码可以将主机号进行再次划分:
- IP = 网络号 + 子网号 + 主机号
- 三级划分比较灵活,可以选择划分,也可以选择不划分,可以选择划分出2部分,4部分,8部分…2^n(n=0,1,2…)
(1) 子网掩码的概念
- 子网掩码 :用于将一个大的IP网络中的主机号划分为若干小的子网络(常用)。
- 指明一个IP地址的哪些位表示的是主机所在的子网
- 指明哪些位表示的是主机的位掩码。
- 子网掩码不能单独使用,必须结合IP地址一起使用
将若干个小网络组合成一个大的局域网(称之为超网技术)。
- 子网掩码的格式:
- 与IP地址一样长的32位无符号整数,是由一串连续的1,后面跟着一串连续的0组成。
- 默认子网掩码的格式:
1的个数与IP地址中网络号的个数一致
0的个数与IP地址中主机号的个数一致。
(2) 默认子网掩码
A类IP地址的默认子网掩码:11111111 00000000 00000000 00000000 ===> 255.0.0.0
B类IP地址的默认子网掩码:11111111 11111111 00000000 00000000 ===> 255.255.0.0
C类IP地址的默认子网掩码:11111111 11111111 11111111 00000000 ===> 255.255.255.0
子网掩码是对主机号做再次划分,D类E类没有主机号,所以没有子网掩码。
C类IP地址的默认子网掩码:11111111 11111111 11111111 00000000 ===> 255.255.255.0
11111111 11111111 11111111 10000000 ===> 255.255.255.128
11111111 11111111 11111111 11000000 ===> 255.255.255.192
11111111 11111111 11111111 11100000 ===> 255.255.255.224
11111111 11111111 11111111 00000011 ===> 1不连续错误的!!!
(3) 格式用法:IP & 子网掩码=子网网段
(1) 1个子网网段
192.168.125.229 & 255.255.255.0
11000000 10101000 01111101 11100101 ===> 192.168.125.229
11111111 11111111 11111111 00000000 ===> 255.255.255.0
------------------------------------------------------------------------------
11000000 10101000 01111101 00000000 ===> 192.168.125.0 子网网段
即192.168.125.229属于192.168.125.0该子网网段。
在00000000-11111111该范围内的主机号,&上255.255.255.0这个子网掩码,得到的结果均为192.168.125.0 子网网段。
即0~255这个范围内的主机号,均为192.168.125.0 子网网段。
所以没有划分出新的子网,所有主机号都在192.168.125.0 子网网段内。
该子网网段可以写作:192.168.125.0/24 (24代表该子网网段是通过有24个1的子网掩码得到)。
这个子网网段内的主机号是多少个 2^8个= 256个。
(2) 2个子网网段
192.168.125.229 & 255.255.255.128
11000000 10101000 01111101 1 1100101 ===> 192.168.125.229
11111111 11111111 11111111 1 0000000 ===> 255.255.255.128
----------------------------------------------------
11000000 10101000 01111101 1 0000000 ===> 192.168.125.128 子网网段
范围:如下范围的主机号[128, 255],& 255.255.255.128得到的结果均为192.168.125.128/25 子网网段。
11000000 10101000 01111101 1 0000000 ===> 192.168.125.128
11000000 10101000 01111101 1 1111111 ===> 192.168.125.255
192.168.125.127 & 255.255.255.128
11000000 10101000 01111101 0 1111111 ===> 192.168.125.127
11111111 11111111 11111111 1 0000000 ===> 255.255.255.128
----------------------------------------------------
11000000 10101000 01111101 0 0000000 ===> 192.168.125.0 子网网段
范围:如下范围的主机号[0, 127],& 255.255.255.128得到的结果均为192.168.125.0/25 子网网段。
11000000 10101000 01111101 0 0000000 ===> 192.168.125.0
11000000 10101000 01111101 0 1111111 ===> 192.168.125.127
综上所述,
通过255.255.255.128可以将192.168.125.0该网络划分出2个子网
每个子网中有2^7个主机号。
特殊的IP地址:
- 每个子网网段中,都有自己的子网网段地址。有效网络号+有效子网号+全是0的主机号 。 掐头
- 每个子网网段中,都有自己的子网广播地址。 去尾
- 总结:每个子网网段都需要掐头去尾
1.4.5 网关
- 网关是一个网络通向其他网络的IP地址
- 目前家用路由器一般使用192.168.1.1和192.168.0.1作为LAN接口的地址,这个两个也是最常用的网关地址。
1.4.6 域名系统
-
由于使用IP地址来指定计算机不方便人们记忆,且输入时候容易出错,用字符标识网络种计算机名称方法。
-
这种命名方法就像每个人的名字,这就是域名(Domian Name)
-
域名服务器(Domain Name server): 用来处理IP地址和域名之间的转换。
-
域名系统(Domain Name System,DNS): 域名翻译成IP地址的软件
-
一个域名,可以绑定多个ip
域名结构
- 例如域名 www.baidu 从右向左看
cn为高级域名,也叫一级域名,它通常分配给主干节点,取值为国家名,cn代表中国
com为网络名,属于二级域名,它通常表示组织或部门
中国互联网二级域名共40个,edu表示教育部门,com表示商业部门,gov表示政府,军队mil等等
baidu为机构名,在此为三级域名,表示百度
www:万维网 world wide web,也叫环球信息网,是一种特殊的信息结构框架。
1.4.7 端口号
- 为了区分一台主机收到的数据包交给哪个进程处理,使用端口号来区分。程序启动后将端口号和进程绑定在一起。
- 网络里面的通讯是由 IP地址+端口号 来决定
- 端口号存储在 2个字节 无符号整数中 (unsigned short int)。[1, 65535]
- 常见的端口号:
1~1023 端口我们编程时候不要使用,是那些 系统/规定 应用程序占了
TCP 21端口:FTP文件传输服务
TCP 23端口:TELNET终端仿真服务
TCP 25端口:SMTP简单邮件传输服务
TCP 110端口:POP3邮局协议版本3
TCP 80端口:HTTP超文本传输服务
TCP 443端口:HTTPS加密超文本传输服务
UDP 53端口:DNS域名解析服务
UDP 69端口:TFTP文件传输服务
- 可以使用的:1024~49151,就是我们平时编写服务器使用的端口号
- 临时端口号:49152~65535,这部分是客户端运行时候动态选择的
TCP和UDP的端口号是相互独立的: 有时TCP和UDP用到了同一个端口,也是能用的
2. 跨主机传输
2.1 字节序(重点!)
2.1.1 字节序的概念
- 字节序是不同类型CPU主机,内存存储 多字节整数 序列的方式。
- char 字符串 float double均没有字节序的说法
- short int long long long有字节序的说法
- 小端字节序:低字节存储在低地址上,高字节存储在高地址上。
- 大端字节序:低字节存储在高地址上,高字节存储在低地址上。
首地址都是低地址,数据的读取都是从低地址往高地址读取,经过大小端转换后得出结果。
2.1.2 本地字节序与网络字节序
本地字节数:主机字节序(Host Byte Order) HBO
网络字节序(Network Byte Order) NBO,网络字节序规定使用大端字节序。
在跨主机传输过程中,需要使用统一的字节序,即网络字节序,避免兼容性问题。
2.1.3 字节序转换函数
2.1.3.1 htons htonl 主机字节序–>网络字节序
头文件:
#include <arpa/inet.h>
uint32_t htonl(uint32_t hostlong);
uint16_t htons(uint16_t hostshort);
参数:
指定要转换成网络字节序的整型:分别是32bit和16bit;
返回值:
成功,返回转换后网络字节序的整型
示例:
#include <stdio.h>
#include <arpa/inet.h>
int main(int argc, const char *argv[])
{
unsigned int a = 0x87654321;
printf("%#x\n", a); //0x87654321
printf("%#x\n", htonl(a)); //0x21436587
printf("%#x\n", htons(a)); //0x2143
return 0;
}
2.1.3.2 ntohs ntohl 网络字节序---->主机字节序
头文件:
#include <arpa/inet.h>
原型:
uint32_t ntohl(uint32_t netlong);
uint16_t ntohs(uint16_t netshort);
参数:
uint32_t hostlong:32位网络字节序整型;
uint16_t hostshort:16位网络字节序整型;
返回值:
成功,返回转换成主机字节序的整型;
2.1.4 结构体对齐
- 编译器会对结构体进行对齐,加速CPU取值周期,由于数据对齐也是与操作系统相关,不同的主机如果使用不同的对齐方式,会导致数据无法解析。
- 所以网络传输结构体的时候需要取消结构体对齐;
例如:
#include <stdio.h>
#pragma pack(1) //设置默认对齐系数 :()中的参数只能填2^n (n=0,1,2,3,4,5......)
typedef struct
{
char a; //1
int b; //4
int d; //4
}_A;
#pragma pack() //重置默认对其系数,重新置为8
typedef struct
{
char a; //1
int b; //4
int d; //4
} __attribute__((packed)) B; //取消结构体对齐
typedef struct
{
char a; //1
//3
int b; //4
int d; //4
}_C;
int main(int argc, const char *argv[])
{
printf("%ld\n", sizeof(_A)); //9
printf("%ld\n", sizeof(_B)); //9
printf("%ld\n", sizeof(_C)); //12
return 0;
}
2.1.5 类型长度
- 因为涉及到跨平台,不同平台会有不同的字长
- int long int不同操作系统这两个数据类型所占的字节数可能是不一样的
- 解决方式:可以通过通用类型:uint8_t uint16_t uint32_t
#include <stdint.h>
typedef struct
{
uint8_t a; //1
uint32_t b; //4
uint16_t d; //2
}_A;
2.2 IP转换
- 由于IP地址本质上是一个4个字节的无符号整数,所以在跨主机传输中也有字节序的概念。
- 所以需要将IP地址转换成网络字节序。
- “192.168.8.189” ---->本机字节序的整型 0xC0A808BD---->网络字节序0xBD08A8C0
- “192.168.31.42”----> 0xC0A81F2A ---->0x2A1FA8C0
2.2.1 点分十进制—>网络字节序
2.2.1.1 inet_aton
- 只能转换IPv4
头文件:
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
原型:
int inet_aton(const char *cp, struct in_addr *inp);
参数:
char *cp:源IP地址的点分十进制字符串,例如 “192.168.1.10”;
struct in_addr *inp:存储转换成网络字节序的IP;
typedef uint32_t in_addr_t;
struct in_addr {
in_addr_t s_addr;
};
返回值:
成功,返回非0;
失败,返回0;
例子:
#define IP "192.168.1.10" //0xC0A8010A
int main(int argc, const char *argv[])
{
struct in_addr inp;
if(inet_aton(IP, &inp) == 0)
{
printf("转换失败\n");
return -1;
}
printf("%#X\n", inp.s_addr); //0X0A01A8C0
return 0;
}
2.2.1.2 inet_pton
- 既可以转IPv4也能处理IPv6
头文件:
#include <arpa/inet.h>
原型:
int inet_pton(int af, const char *src, void *dst);
参数:
int af:协议族
AF_INET IPV4
AF_INET6 IPV6
char *src:指定要转换成网络字节序的点分十进制字符串;
void* dst
typedef uint32_t in_addr_t;
struct in_addr {
in_addr_t s_addr;
};
af == AF_INETa;
struct in6_addr
{
}
返回值:
成功,返回1;
失败,返回0或者-1,更新errno;
例子:
#define IP "192.168.1.3" //0xC0A80103 --> 0x301A8C0
struct in_addr inp;
inet_pton(AF_INET, IP, &inp);
printf("%#X\n", inp.s_addr); //0x301A8C0
2.2.1.3 inet_addr
-
最常用
-
只能转换IPv4
头文件: #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> 原型: uint32_t inet_addr(const char *cp); 参数: char *cp:源IP地址的点分十进制字符串,例如 “192.168.1.10”; 返回值: 成功,返回转换后的网络字节序IP地址; typedef uint32_t in_addr_t; 失败,返回INADDR_NONE (usually -1);
例子:
printf("%#X\n", inet_addr(IP));
2.2.2 网络字节序—>点分十进制
2.2.2.1 inet_ntoa 常用
- 只能转换IPv4;
头文件:
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
原型:
char *inet_ntoa(struct in_addr in);
参数:
struct in_addr in:指定要转换成点分十进制字符串的IP地址;
typedef uint32_t in_addr_t;
struct in_addr {
in_addr_t s_addr;
};
返回值:
成功,返回点分十进制字符串的首地址;
printf("%s\n", inet_ntoa(inp));
2.2.2.2 inet_ntop
头文件:
#include <arpa/inet.h>
原型:
const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);
参数:
int af:协议族
AF_INET IPV4
AF_INET6 IPV6
void* src:存储要转换成点分十进制字符串的IP首地址;
typedef uint32_t in_addr_t;
struct in_addr {
in_addr_t s_addr;
};
af == AF_INETa;
struct in6_addr
{
}
char *dst:存储转换后的结果,点分十进制的首地址;
socklen_t size:缓冲区大小,其实就是指定多大的空间用于转换IP;
返回值:
成功,返回字符串的首地址,就是dst;
失败,返回NULL,更新errno;
例子:
char ip[20];
if(inet_ntop(AF_INET, &inp, ip, sizeof(ip)) == NULL)
{
perror("ient_ntop");
return -1;
}
printf("%s\n", ip);
版权声明:本文标题:嵌入式养成计划-28-网络编程----网络编程基础 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.freenas.com.cn/jishu/1729001930h1305486.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论