目录
一、为什么要学习网络编程?
1. 进程间通信方式
- 内核提供三种:无名管道、有名管道、信号
- System V提供三种:消息队列、共享内存、信号灯集
- 进程间通信:这些通信方式通过内核空间完成,适用于同一主机内的多个进程之间。
- 跨主机通信:由于不同主机有不同的内核空间,以上方式无法支持跨主机的通信。
- 套接字通信:引入了第七种进程间通信方式,完成跨主机多进程通信。
二、网络发展历史
1. 发展阶段
- APRAnet阶段:冷战产物
- TCP/IP协议阶段:最初只有TCP和IP两个协议
- OSI开放系统互联模型
- TCP/IP协议族(重要)
- 量子通信(可能)
2. APRAnet阶段
- 阿帕网是互联网的最早雏形
- 无法互联不同类型的计算机和操作系统
- 缺少纠错功能
3. TCP/IP协议阶段
在计算机网络中,为了确保数据能够有序交换,需要遵循一些事先约定的规则。这些规则明确规定了数据的格式以及同步问题。为了在网络中进行数据交换而建立的规则、标准和约定被称为 网络协议。
联网协议:它是一组定义如何在网络上传输信息的规则。
TCP/IP协议分为两个核心协议:
传输控制协议 (TCP):
- TCP负责检测网络传输中的错误,确保数据的可靠传输。
- 它通过面向连接的方式来传输数据,保证数据完整无误、无丢失、无重复。
- TCP是用于确保通信双方之间可靠数据传输的重要协议。
互联网协议 (IP):
- IP专门负责在不同网络之间进行互联,实现数据的路由和传输。
- 它的主要任务是将数据包从源主机传送到目标主机,确保数据能够通过各种网络进行传递。
通过这两个协议的合作,TCP/IP协议族确保了网络中数据的可靠传输和不同网络之间的互联。
网络通信中的基本规则和约定:
在网络通信中,所谓的“约定俗成的规则”实际上是指一系列标准化的协议和规范,它们定义了数据如何在网络中传输和处理。这些规则类似于数学中的公理和定理,是网络通信的基础。以下是一些网络通信中的基本规则和约定:
分层模型:网络通信通常遵循分层模型,如OSI七层模型或TCP/IP四层模型。每一层都有其特定的功能和协议,并且与相邻层通过接口交互。
数据封装:在发送数据时,每一层都会在数据上添加自己的头部信息,这个过程称为封装。头部信息包含了该层所需的控制信息,如源地址、目的地址等。
数据传输:数据在网络中以帧或包的形式传输。这些帧或包包含了数据本身以及必要的控制信息。
寻址:每个网络设备都有一个唯一的地址(如IP地址),用于标识发送者和接收者。
路由选择:数据包在网络中的传输路径由路由协议决定,这些协议负责选择最佳路径以确保数据的传输。
流量控制:为了控制数据流的速率,防止网络拥塞,网络协议会使用流量控制机制,如滑动窗口协议。
错误检测和纠正:网络协议包括错误检测和纠正机制,如校验和、序列号和重传机制,以确保数据的完整性和正确性。
连接管理:在需要可靠传输的协议中,如TCP,会建立连接、维护连接状态,并在数据传输完成后释放连接。
数据分段和重组:对于大于网络最大传输单元(MTU)的数据,需要在发送前进行分段,并在接收端重新组装。
服务质量(QoS):网络协议可以提供不同的服务质量,以确保关键数据流(如语音和视频)的优先级。
安全性:网络通信中的安全性规则包括加密、认证和访问控制,以保护数据不被未授权访问。
多路复用和解复用:在同一物理介质上,多个数据流可以同时传输,这需要网络协议来管理这些数据流的复用和解复用。
这些规则和约定是网络通信的基础,它们确保了数据能够在复杂的网络环境中高效、可靠地传输。就像数学中的1+1=2一样,这些规则是网络通信中的基本事实,我们不需要深入了解它们为什么是这样,只需要知道它们是网络通信的规则,并按照这些规则来设计和使用网络。
三、 网络体系结构及OSI开放系统互联模型
1. 网络体系结构概念
- 每一层有独立功能,单层不可获取
- 功能相近的协议被组织在一起形成协议栈
- 分层的好处:
- 各层独立,层与层之间只需要通过接口进行交互
- 稳定性和灵活性:当一层发生变化时,其他层不受影响
- 易于实现和维护
- 促进标准化
- 结构上不可分割,各层可以采用最合适的技术来实现
2. OSI开放系统互联模型
- OSI模型是由国际标准化组织(ISO)提出的理想化模型,包含七层:
- 物理层、数据链路层、网络层、传输层、会话层、表示层、应用层
3. TCP/IP协议族的体系结构
-
TCP/IP协议簇是互联网的事实标准,包含四层:
- 应用层:如Telnet、FTP、HTTP、DNS、SMTP等
- 传输层:TCP和UDP
- 网络层:IP、ICMP、IGMP
- 链路层:以太网、令牌环网、FDDI等
-
虽然TCP/IP体系结构只有四层,但其功能与OSI七层模型相同。
4. TCP/IP四层结构与OSI七层模型对应关系
OSI七层模型与TCP/IP四层结构之间有一定的对应关系,如下所示:
OSI层 | 功能 | TCP/IP协议族 |
---|---|---|
应用层 | 文件传输、电子邮件、文件服务、虚拟终端 | TFTP, HTTP, SNMP, FTP, SMTP, DNS, Telnet |
表示层 | 数据格式化、代码转换、数据加密 | 没有协议 |
会话层 | 解除或建立与别的节点的联系 | 没有协议 |
传输层 | 提供端对端的接口 | TCP, UDP |
网络层 | 为数据包选择路由 | IP, ICMP, RIP, OSPF, BGP |
数据链路层 | 传输有地址的帧以及错误检测 | SLIP, CSLIP, PPP, ARP, RARP |
物理层 | 以二进制数据形式在物理媒体上传输数据 | ISO2110, IEEE802.1, IEEE802.2 |
解释
- 应用层(OSI层 7)与TCP/IP模型的应用层对应,涵盖文件传输、电子邮件、文件服务和虚拟终端等协议,如HTTP、FTP、SMTP等。
- 表示层(OSI层 6)负责数据格式化、代码转换和数据加密,在TCP/IP模型中没有明确的对应协议,通常这些功能可以通过应用层协议或其他中间协议实现。
- 会话层(OSI层 5)处理会话的建立和断开,但在TCP/IP模型中也没有单独的协议。这些功能通常由应用层协议来实现。
- 传输层(OSI层 4)在TCP/IP模型中由TCP和UDP协议负责,提供端对端的数据传输。
- 网络层(OSI层 3)由IP、ICMP、RIP、OSPF、BGP等协议处理,负责数据包的路由和转发。
- 数据链路层(OSI层 2)在TCP/IP模型中由SLIP、CSLIP、PPP、ARP、RARP协议管理,负责帧的传输、错误检测等。
- 物理层(OSI层 1)在TCP/IP模型中由协议如ISO2110和IEEE802.x负责,处理在物理媒介上传输的比特流。
这种对比表明,TCP/IP协议族是简化版的网络模型,其将OSI模型的七层合并为四层,省略了表示层和会话层的独立协议功能。
5. 数据封包和拆包的过程
- MTU(最大传输单元):数据大于MTU时,需要分包传输。
- 指令:使用
ifconfig
查看MTU。
6. TCP/IP四层结构中常见的协议
应用层:
- HTTP(超文本传输协议):万维网的数据通信基础
- FTP(文件传输协议):用于文件传输,使用TCP
- TFTP(简单文件传输协议):使用UDP传输
- SMTP(简单邮件传输协议):电子邮件传输协议
传输层:
- TCP:面向连接、可靠、基于字节流的协议
- UDP:无连接、不可靠、快速传输的协议
网络层:
- IP:实现多个网络间的信息传输
- ICMP:用于传递控制消息(如ping命令)
- IGMP:组播协议,用于主机和组播路由器之间的通信
链路层:
- ARP(地址解析协议):通过IP地址获取MAC地址
- RARP(逆向地址解析协议):通过MAC地址获取IP地址
其他相关知识
Linux内核的五大功能:
- 内存管理:分配和回收内存
- 进程管理:时间片轮转、上下文切换
- 文件管理:将二进制数据转换为人类可读的字符
- 设备管理:在Linux中“一切皆文件”
- 网络管理:管理网络协议栈
协议:
- 协议是一组准则,发送方和接收方遵循这些准则进行数据发送和解析。
四、TCP和UDP异同(笔试面试)
共同点:
- TCP和UDP:都属于传输层的协议
TCP —— 稳定
- 提供面向连接的、可靠的数据传输服务
- 传输过程中:
- 数据无误、无丢失、无失序、无重复
- TCP会给每个数据包编上编号(序列号)
- 每个序列号都需要应答包回应,若无应答,则重新发送直到正确为止
- 数据传输效率低,耗费资源多
- 数据收发不同步:
- 为提高效率,TCP会将多个小的、发送间隔短的数据包合并成一个包发送,这一现象称为“沾包”现象
- 该沾包算法称为 Nagle算法
- TCP的使用场景:对传输质量要求较高、需要可靠通信或传输大量数据的场合
- 例如:账户登录、大型文件下载等
UDP —— 快速
- 面向无连接的、不保证数据可靠的协议,尽最大努力传输的协议
- 数据传输过程中,可能出现数据丢失、重复、失序现象
- 数据传输效率高,实时性高
- 限制每次传输的数据大小,超出部分直接忽略
- 收发是同步的,不会发生沾包现象
- UDP的使用场景:适用于发送小尺寸数据,且接收端难以应答的场合
- 例如:广播、音视频通信软件等
TCP 3次握手和4次挥手
TCP三次握手(3-Way Handshake)
TCP连接的建立采用“三次握手”过程完成,确保客户端和服务器之间的连接能够可靠地建立。其过程如下:
客户端发送SYN包
客户端 → 服务器:
客户端发送一个带有SYN标志的数据包到服务器,告诉服务器客户端希望建立连接。这个数据包中会包含一个初始的序列号(seq
)。SYN(seq=x)
服务器响应SYN-ACK包
服务器 → 客户端:
服务器收到客户端的SYN包后,确认收到并准备建立连接。服务器会发送一个SYN-ACK包,其中包含自己的序列号,并确认客户端的序列号(即ack = x + 1
)。SYN-ACK(seq=y, ack=x+1)
客户端确认ACK包
客户端收到服务器的SYN-ACK包后,客户端发送一个带ACK标志的数据包,表示确认建立连接。此时客户端确认服务器的序列号,并将其返回(即ack = y + 1
)。至此,连接建立完成。客户端 → 服务器:
ACK(seq=x+1, ack=y+1)
连接建立完毕,双方可以开始数据传输。
TCP四次挥手(4-Way Handshake)
TCP连接的关闭采用“四次挥手”过程完成,确保双方都能优雅地关闭连接。其过程如下:
客户端发送FIN包
客户端 → 服务器:
客户端想关闭连接时,首先发送一个带FIN标志的数据包,告诉服务器客户端没有数据要发送了,但可能仍然会接收数据。此时,客户端进入FIN_WAIT_1
状态。FIN(seq=u)
服务器确认FIN包
服务器 → 客户端:
服务器收到客户端的FIN包后,发送一个带ACK标志的数据包,表示确认客户端请求关闭连接。服务器进入CLOSE_WAIT
状态,等待将数据传输完毕。客户端处于FIN_WAIT_2
状态。ACK(seq=v, ack=u+1)
服务器发送FIN包
服务器 → 客户端:
服务器准备关闭连接时,发送一个带FIN标志的数据包,告诉客户端自己没有数据要发送了。此时,服务器进入LAST_ACK
状态。FIN(seq=w)
客户端确认FIN包
客户端收到服务器的FIN包后,发送一个带ACK标志的数据包,表示确认关闭连接。客户端进入TIME_WAIT
状态,等待足够的时间确保服务器收到确认包后再完全关闭连接。服务器进入CLOSED
状态,连接完全关闭。客户端 → 服务器:
ACK(seq=u+1, ack=w+1)
连接关闭完毕。
通过三次握手和四次挥手,TCP能够确保数据传输的可靠性和连接的有序关闭。
标志位解释
在TCP三次握手和四次挥手中,SYN、SYN-ACK、ACK、FIN都是标志位,用来控制连接的建立和断开。以下是它们的英文全称及含义:
SYN (Synchronize)
用于同步序列号,表示请求建立连接。客户端向服务器发送SYN包,请求建立连接时,初始化一个序列号。SYN-ACK (Synchronize-Acknowledge)
是服务器对SYN包的回应,表示服务器同意建立连接,并确认客户端发送的SYN包。服务器会为连接分配一个序列号,并通过ACK确认收到客户端的SYN。ACK (Acknowledge)
确认包,表示确认收到数据或请求。无论是在三次握手中的最后一步,还是四次挥手中的中间步骤,ACK用于确认双方的数据传输。FIN (Finish)
终止标志位,表示请求关闭连接。客户端或服务器发送FIN包,表示没有数据要发送,准备关闭连接。
总结:
- 三次握手: 主要用于连接的建立,确保双方都能接收和发送数据。
- 四次挥手: 主要用于连接的关闭,确保数据传输完成后双方都可以正常关闭连接。
- SYN:同步连接请求。
- SYN-ACK:对同步请求的确认响应。
- ACK:确认消息,表示接收到数据或请求。
- FIN:终止连接请求。
五、网络基础相关的概念
5.1 字节序
-
主机字节序(Endianness):不同类型的CPU在处理多字节整数时有两种存储方式:
- 大端存储(Big Endian):高位字节存储在低地址端。
- 小端存储(Little Endian):低位字节存储在低地址端。
-
判断主机是大端还是小端存储: 使用联合体
union
判断主机字节序,例子中的mmm.n = 0x87654321;
会在内存中存储为87 65 43 21
。若字节序为大端,输出为87
;若为小端,输出为21
。typedef union { int n; char a; } kkk; int main(int argc, const char *argv[]) { kkk mmm; mmm.n = 0x87654321; char *p = &mmm.a; p = p + 3; printf("*p = %d\n", *p); if (mmm.a == 0x87) { printf("大端\n"); } if (mmm.a == 0x21) { printf("小端\n"); } return 0; }
-
手动将小端存储转换为大端存储: 通过交换字节顺序的方式手动转换小端到大端。
typedef union { int n; char a[4]; } kkk; int main(int argc, const char *argv[]) { kkk mmm; mmm.n = 0x87654321; char *p1 = &mmm.a; char *p2 = p1 + 3; char t; t = *p1; *p1 = *p2; *p2 = t; p1++; p2--; t = *p1; *p1 = *p2; *p2 = t; printf("%#x\n", mmm.n); return 0; }
-
网络字节序:
- 在网络中,传输数据时,多字节整数需遵循网络字节序(大端存储)。无论主机字节序是大端还是小端,发送的数据都会转换为网络字节序。
- 系统提供的字节序转换函数:
htonl(uint32_t hostlong)
:主机字节序转网络字节序(4字节)。htons(uint16_t hostshort)
:主机字节序转网络字节序(2字节)。ntohl(uint32_t netlong)
:网络字节序转主机字节序(4字节)。ntohs(uint16_t netshort)
:网络字节序转主机字节序(2字节)。
示例代码:
#include <arpa/inet.h> int main(int argc, const char *argv[]) { int num = 0x12345678; // 4字节整数 int k = htonl(num); // 主机转网络字节序 printf("%x\n", k); printf("%x\n", ntohl(k)); // 网络转主机字节序 return 0; }
5.2 IP地址的转换
inet_addr
:将点分十进制的IP地址转换为网络字节序的二进制数据。inet_ntoa
:将网络字节序的IP地址转换为点分十进制形式。
示例代码:
#include <arpa/inet.h> int main(int argc, const char *argv[]) { in_addr_t kkk = inet_addr("192.168.1.1"); // IP转网络字节序 printf("%x\n", kkk); struct in_addr mmm; mmm.s_addr = kkk; char *p = inet_ntoa(mmm); // 网络字节序转IP printf("%s\n", p); return 0; }
5.3 子网掩码
-
子网掩码的概念:
- 子网掩码用于划分网络与主机的部分,进一步分割网络空间,确定每个IP地址属于哪个子网。
- IP地址的格式:
IP地址 = 网络号 + 子网号 + 主机号
。
-
子网掩码的例子:
- 默认子网掩码:
- C类网络:
255.255.255.0
,对应网络部分24位,主机部分8位。 - A类网络:
255.0.0.0
,对应网络部分8位,主机部分24位。 - B类网络:
255.255.0.0
,对应网络部分16位,主机部分16位。
- C类网络:
示例:
192.168.125.161
与子网掩码255.255.255.0
进行与运算,得到子网网段为192.168.125.0
。 - 默认子网掩码:
-
CIDR表示法:
- CIDR(Classless Inter-Domain Routing)表示法使用斜杠后跟子网掩码的位数,例如
192.168.125.128/25
。
- CIDR(Classless Inter-Domain Routing)表示法使用斜杠后跟子网掩码的位数,例如
-
特殊IP地址:
- 网络地址:如
192.168.125.0
,表示网络本身,无法分配给主机。 - 广播地址:如
192.168.125.255
,用于广播数据包。 - 网关地址:如
192.168.125.1
,通常是子网的网关地址。
- 网络地址:如
5.4 端口号
-
端口号:
- 端口号是主机中某个进程的标识,TCP和UDP通信时,通过端口号来区分不同的进程。
- 端口号范围:
0
到65535
。- 知名端口:
0-1023
(例如 HTTP 80、FTP 21)。 - 注册端口:
1024-49151
(用于应用程序)。 - 动态端口:
49152-65535
(客户端使用)。
- 知名端口:
-
TCP和UDP端口号是独立的,即一个IP地址可以同时通过TCP和UDP协议使用不同的端口号。
5.5 域名解析
-
域名:
- 用字符标识网络中的计算机,类似于人的名字,易于记忆和输入。
-
DNS(域名系统):
- 域名和IP地址之间的转换通过DNS完成。
- DNS服务器:负责将域名解析为对应的IP地址。
-
域名结构:
- 域名从右到左分为不同的层级:
com
(顶级域名,TLD),如.com
表示商业组织。baidu
(二级域名)。www
(三级域名)。
- 域名从右到左分为不同的层级: