一.网络基础
1.网络编程的概念
- 网络编程(Network Programming)是指编写能够通过网络进行通信的软件的过程。网络编程涉及使用各种编程语言和技术,创建能够在不同设备之间传输数据的应用程序。
- 客户端-服务器模型(Client-Server Model):
客户端:发起通信请求的一方,例如用户的浏览器。
服务器:响应客户端请求并提供资源或服务的一方,例如存储网页的服务器。
- 协议(Protocol):
网络通信必须遵循的规则和标准。例如,HTTP、HTTPS、FTP、TCP、UDP等。 - 套接字(Socket):
套接字是通信的端点,允许程序通过网络发送和接收数据。
TCP套接字:提供可靠的、面向连接的通信。
UDP套接字:提供不可靠的、无连接的通信。
- IP地址和端口号(IP Address and Port Number):
IP地址:唯一标识网络中的每台设备。
端口号:标识设备上特定的服务或应用程序。例如,HTTP服务通常使用端口80。
服务/协议 | 端口号 | 描述 |
---|---|---|
HTTP | 80 | 用于未加密的网页浏览 |
HTTPS | 443 | 用于加密的网页浏览 |
FTP | 20 | 用于数据传输 |
21 | 用于控制连接 | |
SMTP | 25 | 用于发送电子邮件 |
POP3 | 110 | 用于接收电子邮件 |
IMAP | 143 | 用于接收电子邮件,支持更多功能 |
DNS | 53 | 用于域名解析 |
Telnet | 23 | 用于远程登录(不推荐使用,因不安全) |
SSH | 22 | 用于安全的远程登录 |
DHCP | 67 | 服务器端 |
68 | 客户端 |
-
数据传输(Data Transmission):
数据在网络上传输时可能需要被分成多个数据包,每个数据包通过不同的路径传输,最终在接收端重新组装。
-
同步与异步通信(Synchronous and Asynchronous Communication):
同步通信:发送方在等待接收方的响应之前不会进行其他操作。
异步通信:发送方在等待响应时可以继续进行其他操作。
- 网络安全(Network Security):
包括加密、认证、防火墙等技术,确保数据在传输过程中不被篡改或盗取。 - 常见的网络编程接口和库:
BSD Sockets:Unix系统上广泛使用的套接字编程接口。
Winsock:Windows系统上的套接字编程接口。
高层次网络编程库:如Python的socket模块、Java的java.net包等。
- 网络七层模型
层次 | 名称 | 功能描述 | 示例协议及设备 |
---|---|---|---|
第七层 | 应用层(Application) | 为应用程序提供网络服务,直接为用户提供接口。 | HTTP、FTP、SMTP、DNS、Telnet |
第六层 | 表示层(Presentation) | 负责数据的格式化、加密和解密、数据压缩。 | SSL/TLS、JPEG、MPEG |
第五层 | 会话层(Session) | 管理和控制会话(连接),建立、管理和终止会话。(主机之间的会话管理) | NetBIOS、RPC |
第四层 | 传输层(Transport) | 提供端到端的可靠传输,处理数据包的错误校验和流量控制。(指定哪个进程接受,哪个进程发送) | TCP、UDP |
第三层 | 网络层(Network) | 负责路径选择和逻辑地址(IP地址)的路由选择和转发。(找主机的) | IP、ICMP、IGMP |
第二层 | 数据链路层(Data Link) | 负责节点到节点的数据传输,处理物理地址(MAC地址)的传输和错误检测。(将数据包拆分成数据帧) | Ethernet、PPP、Switch、Bridge |
第一层 | 物理层(Physical) | 负责媒介、信号的传输和接收,定义物理连接接口和传输介质的标准。(二进制比特流传输) | 光纤、铜线、网卡、Hub |
用户空间:用户层、表示层、会话层
内核空间:传输层、网络层、数据链路层、物理层
**交互流程示例**
1.用户在浏览器(应用层)中输入一个网址。
2.浏览器通过操作系统提供的套接字接口建立一个TCP连接(传输层)。
3.TCP协议在内核空间处理,选择合适的路由(网络层)。
4.数据链路层将数据帧传输到相邻节点(交换机或路由器)。
5.物理层将数据以电信号或光信号的形式传输。
五层模型介绍
- 网络接口与物理层也叫网络访问层
功能:将IP地址与物理地址MAC映射,以及将上一层的ip报文封装成帧,转换为二进制比特流传输
ARP:通过IP地址获取其对应的MAC地址
RARP:通过MAC地址获取其对应的IP地址
MTU:最大传输单元:1500bytes
MSS:最大报文长度:1460bytes - 网络层
- 负责在主机之间的通讯中选择数据包传输的路径,即选择路由
- IP协议(Internet Protocol)
ip协议根据数据包的目的地址来决定如何投递数据包 - ICMP协议
ICMP(Internet Control Message Protocol,互联网控制报文协议)是一种网络层协议,主要用于在计算机网络中传递控制消息和错误报告。ICMP 协议是 TCP/IP 协议族的一部分,主要为 IP 协议提供支持,确保数据包在网络中的正确传输。
- 传输层
- 负责提供应用程序之间的通讯服务,这种服务又称为端到端,只关心通讯的起始端和目的端,并不在乎数据包的传输中的过程
- tcp协议
TCP(Transmission Control Protocol,传输控制协议)是一种面向连接的、可靠的、基于字节流的传输层协议,属于 TCP/IP 协议族的一部分。它提供了可靠的数据传输和流量控制机制,确保数据从源端到目的端的可靠传输。
- 应用层
- 负责处理应用程序的逻辑,提供函数接口
- HTTP/HTTPS
超文本传输协议,万维网数据通信的基础
http:明文发送;https加密传输 - 邮件协议
收:POP3
发:SMTP
- HTTP/HTTPS
网络封包与拆包
TCP
- 提供面向连接的,可靠的数据传输服务。
- 数据无误,无丢失,无失序,无重复到达的通信
- 会给每一个数据包编上一个编号,该编号称之为序列号
- 每一个数据包都需要对应的应答包进行应答。若应答错误,或者根本没有应答则会触发超时重传机制。
- TCP效率低下,耗费资源多。
- TCP限制数据包的大小,超出部分需要分帧处理
- 粘包现象:数据的发送和接收是不同步的。
- 将多个比较小,且发送间隔短的数据包,粘成一个包进行发送,减少应答次数。该现象称之为粘包现象。该算法称之为nagle算法。
适用场景:TCP适用于对传输质量要求比较高的,以及传输大量数据的通信。
在需要可靠数据传输的场景,一般使用TCP。
- TCP报文首部
UDP
- UDP(User Datagram Protocol,用户数据报协议)是一种简单的传输层协议,属于 TCP/IP 协议族中的一部分。与 TCP 不同,UDP 是一种无连接的协议,它不提供可靠性、流量控制或拥塞控制。
- 提供无连接的,不保证可靠的,尽力的传输协议。
- 数据有可能在传输过程中丢失,失序,重复到达等情况。
- 传输效率高。
- 限制每次传输的数据大小。超出部分直接删除。
- 无粘包情况。数据的发送和接收是同步的。
- 实时应用:如语音通话、视频会议、在线游戏等需要快速传输和实时性的应用场景。
简单查询和响应:如 DNS 查询、SNMP 管理等,这些应用可以容忍一定程度的数据丢失。
广播和多播:用于向多个设备传送相同数据的场景,如实时视频流。
- 源端口号和目标端口号用于标识发送端和接收端的应用程序,通过端口号来区分不同的应用。
- 长度字段指定了 UDP 数据报的总长度,包括 UDP 头部和数据部分的长度。最小长度是 8 字节(UDP 头部的固定长度),如果没有数据,则长度为 8 字节。
- 校验和字段用于检测数据报在传输过程中是否有错误。UDP 的校验和是可选的,如果不计算校验和,则填充为全 0。
- 数据字段是实际需要传输的应用数据。UDP 作为一种简单的传输层协议,它不对数据进行分段或者重新组装,也不保证数据的可靠性和顺序性。
IP地址
- IP 地址(Internet Protocol Address,互联网协议地址)是网络中用于标识和定位设备(如计算机、路由器)的唯一地址。它是 TCP/IP 协议族中网络层的基本组成部分,用于在网络中准确定位设备以进行通信。
- IP地址是路由器下发的(自动,手动)
- IP地址的作用:唯一标识、路由选择、地址解析
- WAN:(Wide Area Network,广域网)
- LAN:(Local Area Network,局域网)
IP地址的分类
- IPv4:IPv4 使用 32 位二进制数表示,通常以点分十进制(dotted decimal)的形式显示,每个段(octet)用十进制数表示,范围从 0 到 255。例如,192.168.1.1 是一个常见的 IPv4 地址。
分类 | 说明 |
---|---|
公有 IP 地址 | 用于公共互联网上的设备,由互联网服务提供商(ISP)分配。 |
私有 IP 地址 | 用于局域网内部的设备通信,例如,192.168.x.x 和 10.x.x.x 等地址段。 |
保留 IP 地址 | 用于特定用途的保留地址,如 127.0.0.1 用于本地回环测试。0.0.0.0:表示“这个网络”或“本地主机”,通常用于定义默认路由或表示主机本身。 |
广播地址 | 255.255.255.255:全网广播地址,用于将数据包发送到当前网络的所有主机。 |
- IPv6:IPv6 使用 128 位二进制数表示,共16个字节,采用冒号分隔的八组十六进制数表示,每组十六进制数是 16 位,总长度为 128 位。例如,2001:0db8:85a3:0000:0000:8a2e:0370:7334 是一个 IPv6 地址。
- IPv6地址的简写是将其标准形式(用冒号分隔的十六进制数)缩短的一种方法,以便于阅读和书写。
简写规则
去掉前导零:每个十六进制段中的前导零可以被省略。例如:
2001:0db8:0000:0042:0000:8a2e:0370:7334
简写为:2001:db8:0:42:0:8a2e:370:7334
使用双冒号“::”替代连续的零段:一个IPv6地址中可以使用一次双冒号“::”来替代连续的零段,只能有一次“::”。
例如:
2001:0db8:0000:0000:0000:0000:1428:57ab
简写为:2001:db8::1428:57ab
- IPv4和IPv6不兼容
IP地址划分
- 子网掩码用于划分网络和主机部分,通过与IP地址进行按位与运算来确定网络地址。
- 任意一个IP地址都可以通过软件或者路由器下分局域网
A类地址
- 范围:1.0.0.0 至 126.0.0.0
- 默认子网掩码:255.0.0.0
- 网络位长度:8位
- 主机位长度:24位
- 可用网络数量:128(去掉0和127)
- 每个网络的主机数量:2^24 - 2(去掉全0和全1)
B类地址
- 范围:128.0.0.0 至 191.255.0.0
- 默认子网掩码:255.255.0.0
- 网络位长度:16位
- 主机位长度:16位
- 可用网络数量:16,384(2^14)
- 每个网络的主机数量:2^16 - 2(去掉全0和全1)
C类地址
- 范围:192.0.0.0 至223.255.255.0
- 默认子网掩码:255.255.255.0
- 网络位长度:24位
- 主机位长度:8位
- 可用网络数量:2,097,152(2^21)
- 每个网络的主机数量:2^8 - 2(去掉全0和全1)
D类地址
- 范围:224.0.0.0 至239.255.255.255
- 用途:多播(Multicasting)
E类地址
- 范围:240.0.0.0 至 255.255.255.255
- 用途:保留用于未来或实验目的
ABC中的特殊IP地址
- 网络地址:代表一整个网络的IP地址;有效网络号+主机号全为0;
- 广播地址:向该IP地址发送数据,代表给当前局域网下的所有主机发送数据;有效网络号+全是1的主机号
- 网关是一个网络通向其他网络的IP地址,目前家用路由器一般使用主机号为1的IP地址作为网关
子网计算
- 可以通过改变子网掩码的长度来划分子网。例如,对于一个C类网络192.168.1.0/24,可以通过使用255.255.255.128(/25)将其划分为两个子网,每个子网有128个地址。
- IP=网络号 + 子网号 + 主机号
- 子网掩码&IP地址==子网网段=子网网络地址
域名系统
- 域名服务器(Domain Name server):用来处理IP地址和域名之间的转换。
- 域名系统(Domain Name System,DNS):域名翻译成IP地址的软件
- 一个域名可以有多个IP地址
- 域名从右往左区分一级、二级域名之类:例如
www.example.com 中:
www 是三级域名
example 是二级域名
com 是一级域名
blog.example.co.uk 中:
blog 是三级域名
example 是二级域名
co.uk 是一级域名(.uk 为国家和地区顶级域名,co 是其下的子域)
- 域名空间
- DNS服务器
1. 根域名服务器:管理根域并指向各个顶级域的服务器。
2. 顶级域名服务器:管理顶级域并指向下一级域的服务器。
3. 权威DNS服务器:对某一特定域名具有最终解释权,存储该域名及其子域名的IP地址。
4. 递归DNS服务器:负责处理用户的查询请求,递归地查询其他DNS服务器,直到获得最终结果。
端口号
- 为了区分一台主机收到的数据包交给哪个进程处理,使用端口号来区分。程序启动后将端口号和进程绑定在一起。
- 网络里面的通讯是由 IP地址+端口号 来决定
- 端口号存储在 2个字节 无符号整数中 (unsigned short int)。[1, 65535]
- 1~1023 端口我们编程时候不要使用,是那些”VIP“应用程序占了,也称为熟知端口号
端口号 | 用途 |
---|---|
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文件传输服务 |
- TCP和UDP的端口号是相互独立的
可以使用的:1024~49151,就是我们平时编写服务器使用的端口号
临时端口号:49152~65535,这部分是客户端运行时候动态选择的
跨主机传输
-
不同类型的CPU主机,内存存储 多字节整数 序列的方式
a.float char char类型数组没有字节序的说法。
b.short int , int , long, long long有字节序 -
字节序(Endianness)是计算机系统中数据的存储和传输方式之一,描述了多字节数据(如整数和浮点数)在内存中的排列顺序。主要有两种字节序:大端字节序(Big-endian)和小端字节序(Little-endian)。
-
大端字节序(Big-endian)
在大端字节序中,数据的最高有效字节(Most Significant Byte, MSB)存储在内存的最低地址。换句话说,字节序列从左到右按数值大小排列。举例来说,假设有一个4字节的整数0x12345678:
内存地址低位:[12]
内存地址高位:[34]
更高位:[56]
最高位:[78]
在内存中的排列顺序是:
0x12 0x34 0x56 0x78
- 小端字节序(Little-endian)//有利于正常看出
在小端字节序中,数据的最低有效字节(Least Significant Byte, LSB)存储在内存的最低地址。即字节序列从右到左按数值大小排列。对于同样的4字节整数0x12345678:
内存地址低位:[78]
内存地址高位:[56]
更高位:[34]
最高位:[12]
在内存中的排列顺序是:
0x78 0x56 0x34 0x12
举例说明
假设你有一个16位的整数0x1234,需要存储到内存中:
大端字节序:
内存地址低位:[12]
内存地址高位:[34]
在内存中的排列顺序是:
0x12 0x34
小端字节序:
内存地址低位:[34]
内存地址高位:[12]
在内存中的排列顺序是:
0x34 0x12
-
字节序的影响
字节序影响跨平台数据传输和文件存储格式。不同系统可能采用不同的字节序,导致在数据交换时需要考虑字节序的转换。 -
检测和转换字节序
在编程中,可以通过检测和转换字节序来确保数据在不同平台之间正确传输和处理。例如,在C语言中,可以使用如下方法检测系统的字节序:
#include <stdio.h> // 包含标准输入输出库的头文件
int main() {
unsigned int x = 1; // 定义一个无符号整数变量 x 并将其赋值为 1
char *c = (char*)&x; // 定义一个字符指针 c,并将 x 的地址强制转换为 char* 类型赋值给 c
// 判断 x 变量的最低字节的值
if (*c) { // 通过解引用指针 c 获取 x 变量的第一个字节的值
// 如果第一个字节的值为非零,表示系统是小端字节序
printf("Little-endian\n"); // 输出 "Little-endian"
} else {
// 如果第一个字节的值为零,表示系统是大端字节序
printf("Big-endian\n"); // 输出 "Big-endian"
}
return 0; // 返回 0,表示程序正常结束
}
- 本地字节序与网络字节序
本地字节序:主机字节序(Host Byte Order) HBO,主机本身的字节序成为本地字节序,一般电脑都是小端
网络字节序(Network Byte Order) NBO,网络字节序规定使用大端字节序。
在跨主机传输过程中,需要使用统一的字节序,即网络字节序,避免兼容性问题。 - 字节序转换函数
1)htons htonl 主机字节序–>网络字节序
htons 是 “Host to Network Short” 的缩写。它是一个函数,用于将主机字节序转换为网络字节序。该函数通常在网络编程中使用,以确保数据在不同主机之间传输时的字节序一致。
头文件:
#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)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位网络字节序整型;
返回值:
成功,返回转换成主机字节序的整型;
- IP转换
由于IP地址本质上是一个4个字节的无符号整数,所以在跨主机传输中也有字节序的概念。
所以需要将IP地址转换成网络字节序。
“192.168.8.189” ---->本机字节序的整型 0xC0A808BD---->网络字节序0xBD08A8C0
“192.168.31.42”----> 0xC0A81F2A ---->0x2A1FA8C0
“192.168.124.200” —> 0xC0A87CC8 ---->网络:0xC87CA8C0
- 点分十进制—>网络字节序
- inet_addr 最常用
头文件:
#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);
只能转换IPv4;
例子:
printf("%#X\n", inet_addr(IP));
- 网络字节序—>点分十进制
- inet_ntoa 常用
头文件:
#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;
};
返回值:
成功,返回点分十进制字符串的首地址;
只能转换IPv4;
printf("%s\n", inet_ntoa(inp));
- uint32_t 是 C 语言标准库中定义的一种数据类型,表示一个 32 位的无符号整数。它来自于 stdint.h 头文件,该文件定义了一组具有明确宽度的整数类型。这些类型主要用于编写可移植的代码,因为它们在不同的平台上具有相同的大小和表示范围。
#include<stdint.h>
typedef struct
{
uint8_t a;
uint32_t b;
uint16_t d;
}A;