OSI七层模型-TCP/IP模型

各个层级协议
| 层级 | 协议 |
|---|---|
| 应用层 | http、ftp、nfs、ssh、telnet |
| 传输层 | tcp、udp |
| 网络层 | IP、ICMP、IGMP |
| 链路层 | 以太网帧协议、ARP |
C/S、B/S模型优缺点
| C/S | B/S | |
|---|---|---|
| 优点 | 缓存大量数据、协议选择灵活、速度快 | 安全性较高、跨平台、开发工作量小 |
| 缺点 | 开发工作量较大、安全性、不能跨平台 | 不能缓存大量数据、阉割遵守http协议 |
网络传输流程
数据没有封装之前,是不能在网络中传递
数据-应用层-传输层-网络层-链路层 网络环境
协议简介
以太网帧协议
- ARP:根据IP地址获取mac地址
- 以太网帧协议:根据MAC地址,完成数据包传输
IP协议
版本:IPv4、IPv6
TTL
- time to live
- 设置数据包在路由节点中的跳转上限。每经过一个路由 节点,该值-1,减为0的路由有义务将该数据包丢弃
源IP:32位 — 4字节 192.168.1.108—点分十进制
目的IP:32位—-4字节
IP地址可以在网络环境中唯一标识一台主机
端口号:可以在网络的一台主机上,唯一的标识一个进程
IP地址+端口号:唯一标识一个进程
UDP
- 16位源端口号
- 16位目的端口号
TCP
- 16位源端口号
- 16位目的端口号
- 32位序号
- 32确认序号
- 6个标志位
- 16位窗口大小 2^16=65536
网络套接字
小端法(本地字节序)
高位高地址、低位低地址
int a = 0x12345678
大端法(网络字节序)
- 高位低地址、低位高地址
htonl –> 本地 –> 网络(IP)
htons –> 本地 –> 网络(port)
ntohl –> 网络(IP) –> 本地
ntohs –> 网络(port) –> 本地
IP地址转换
int inet_pton(int af, const char *src, void *dst);
- 本地字节序转换为网络字节序
- af:AF_INET、AF_INET6
- src:IP地址(点分十进制)
- dst:传出:转换后的网络字节序 IP地址
- 返回值:
- 成功返回 1
- 异常返回 0,说明src指向的不是一个有效的ip地址
- 失败返回 -1
const char *inet_ntop(int af, const void *src,char *dst, socklen_t size);
本地字节序转换为网络字节序
af:AF_INET、AF_INET6
src:网络字节序IP地址
dst:本地字节序
size:dst的大小
返回值:
- 成功返回 dst
- 失败返回 NULL
sockaddr地址结构
1 | struct sockaddr_in addr; |
socket模型穿件流程图
一个服务端和一个客户端建立通信一共三个套接字
服务端、客户端
服务端:
- bind()绑定ip+port
- listen()设置同时监听上限
- accept()阻塞监听客户端连接
- 客户端:
- connect()绑定ip+port
套接字函数
1 |
|
TCP通信流程分析
| server | client | ||
|---|---|---|---|
| socket() | 创建socket | socket() | 创建socket |
| bind() | 绑定服务器地址结构 | connect() | 与服务器建立连接 |
| listen() | 设置监听上限 | write() | 写数据到socket |
| accept() | 阻塞监听客户端连接 | read() | 读数据 |
| read() | 读socket获取客户端数据 | close() | |
| write() | 写数据 | ||
| close() | 关闭套接字 |
TCP协议
三次握手
- 主动发起连接请求端,发送 SYN 标志位,请求建立连接。携带数据包包号、数据字节数(0)、滑动窗口大小。
- 被动接受连接请求端,发送 ACK 标志位,同时携带 SYN 请求标志位。携带序号、确认序号、数据字节数(0)、滑动窗口大小。
- 主动发起连接请求端,发送 ACK 标志位,应答服务器连接请求。携带序号、确认序号

四次挥手
- 主动关闭连接请求端,发送 FIN 标志位。
- 被动关闭连接请求端,应答 ACK 标志位。 —–半关闭完成
- 被动关闭连接请求端,发送 FIN 标志位。
- 主动关闭连接请求端,应答 ACK 标志位 。——连接全部关闭

- 滑动窗口
- 发送给连接对端,本段缓冲区实时大小,保证数据不会丢失
TCP状态时序图

主动发起连接请求端:CLOSE — 发送SYN — SYN_SEND — 接收ACK、SYN — SYN_SEND — 发送方ACK — ESTABLISHED(数据通信状态)
主动关闭连接请求端:ESTABLISHED(数据通信状态) — 发送FIN — FIN_WAIT_1— 接收ACK — FIN_WAIT_2 — 接收对端发送的FIN — FIN_WAIT_2 — 回发ACK — TIME_WAIT(只有主动关闭连接方,会经历该状态) — 等2MSL时长 — CLOSED
被动接收连接请求端:CLOSE — LISTEN — 接收SYN — LISTEN — 发送ACK、SYN — SYN_RCVD — 接收ACK — ESTABLISHED
被动关闭连接请求端:ESTABLISHED—接收对端FIN — ESTABLISHED — 发送ACK — CLOSE_WAIT(说明对端(主动关闭连接端)处于半关闭状态) — 发送FIN — LAST_ACK — 接收ACK — CLOSE
重点记忆: ESTABLISHED、FIN_WAIT_2 、CLOSE_WAIT、TIME_WAIT(2MSL时长)
2MSL时长
一定出现在主动关闭连接请求一端
保证,最后一个ACK能被成功接收。(等待期间,对端没有接收到ACK,对端会再次发送FIN请求)
端口复用
1 | int opt = 1; //设置端口复用 |
半关闭
通信双方只有一端关闭通信。——FIN_WAIT_2(半关闭状态)
close(cfd);
1 | int shutdown(itn fd, int how) |
区别:
- shutdown在关闭多个文件描述符应用的文件时,采用全关闭的方法,close只关闭一个
错误处理函数
封装目的
- 在server.c编程过程中突出裸机,将出错处理与逻辑分开,可以直接跳转man手册
wrap.c
- 存放网络信相关常用 自定义函数
- 命名方式:
- 系统调用函数首字母大写 方便查看man手册。如:Listen()、Accept()
- 函数功能:调用系统调用函数,处理出错场景
- 在server.c 和 client.c 中调用 自定义函数
- server.c 和 wrap.c 生成 server
- client.c 和 wrap.c 生成 client
wrap.h
- 存放 网络通信相关常用 自定义函数原神(声明)
高并发服务器
多进程并发服务器
1 | Socket(); //创建监听套接字 lfd |
子进程
- close(lfd); //关闭用于建立连接的套接字
- read();
- upper();
- write();
父进程
注册信号捕捉函数:SIGCHLD
在回调函数中,完成子进程回收
while ( waitpid());
多线程并发服务器
1 | Socket(); //创建监听套接字 lfd |
read函数返回值
- 大于0 实际读到的字节数
- 等于0 已经读到结尾(对端已经关闭)【重点】
- -1 应该进一步判断errno的值
- errno= EAGAIN or EWOULDBLOCK:设置了非阻塞方式读。没有数据到达
- errno= EINTR 慢速系统调用被 中断
- errno= “其他情况” 异常。
select多路IO转接
- 原理:借助内核,select来监听,客户端连接、数据通 信事件
1 | /** |
思路分析:
1 | lfd = socket(); //创建套接字 |