当前位置: 首页 > news >正文

嵌入式学习Day33

bs模型与cs模型的区别

**bs模型(Browser/Server模型)cs模型(Client/Server模型)**是两种常见的软件架构模式,它们在结构、部署和维护等方面存在显著差异。以下是两者的主要区别:

架构差异

bs模型基于浏览器作为客户端,所有业务逻辑和数据处理集中在服务器端,客户端仅负责展示和用户交互。典型的bs应用包括网页邮箱、在线办公工具等。

cs模型需要安装独立的客户端软件,客户端承担部分业务逻辑和数据处理,服务器端负责核心数据管理和服务提供。常见的cs应用包括桌面游戏、传统ERP系统等。

部署与维护

bs模型的客户端无需安装,只需浏览器即可访问,升级和维护仅在服务器端完成,降低了用户端的维护成本。

cs模型的客户端需要单独安装和升级,每次更新可能涉及用户端的软件更新,维护成本相对较高。

性能与资源占用

bs模型的性能依赖于网络环境和服务器负载,客户端资源占用较少,适合轻量级应用。

cs模型可以充分利用客户端硬件资源,处理复杂计算和图形渲染时性能更优,适合对性能要求较高的应用

跨平台兼容性

bs模型天然具备跨平台特性,只要设备支持现代浏览器即可运行,兼容性较好。

cs模型通常需要针对不同操作系统开发特定版本,跨平台支持相对复杂。

网络依赖

bs模型高度依赖网络连接,离线状态下功能受限或无法使用。

cs模型部分功能可离线运行,数据同步可在网络恢复后进行。

  1. 性能表现

    • BS资源消耗集中在服务器端 $$ T_{\text{响应}} = T_{\text{网络}} + T_{\text{服务器处理}} $$
    • CS可分担计算到客户端($本地计算 + 数据缓存$)
  2. 安全性

    • CS可采用私有加密协议($AES-256 + 自定义封装$)
    • BS依赖HTTPS等标准安全机制
  3. 典型应用

    • BS:Web邮箱、在线文档
    • CS:大型游戏、专业设计软件

选择依据:

  • 当需要快速迭代、跨平台访问时优先BS
  • 对性能要求高、需要复杂交互时考虑CS

P2P模型概述

P2P(Peer-to-Peer)模型是一种分布式网络架构,节点(peers)直接通信与共享资源,无需依赖中央服务器。其核心特点是去中心化、高扩展性和容错性,广泛应用于文件共享、区块链、实时通信等领域。

关键特点

  1. 去中心化:节点平等参与,无单点故障风险。
  2. 资源共享:节点既是资源提供者(server)又是消费者(client)。
  3. 自组织性:网络动态调整,节点可自由加入或退出。

常见类型

  • 纯P2P:无中心节点,如比特币网络。
  • 混合P2P:部分依赖服务器协调,如Skype。
  • 结构化P2P:使用分布式哈希表(DHT)组织节点,如Chord协议。
  • 非结构化P2P:随机连接节点,如Gnutella。

TCP:

三次握手四次挥手示意图:

TCP三次握手

TCP三次握手是建立连接的过程,确保双方能够正常通信。具体步骤如下:

客户端发送SYN报文,序列号为x,进入SYN_SENT状态。SYN报文表示请求建立连接。

服务器收到SYN报文后,回复SYN+ACK报文,序列号为y,确认号为x+1,进入SYN_RCVD状态。SYN+ACK报文表示确认客户端的请求并同意建立连接。

客户端收到SYN+ACK报文后,发送ACK报文,序列号为x+1,确认号为y+1,进入ESTABLISHED状态。服务器收到ACK报文后也进入ESTABLISHED状态。

客户端 -> 服务器: SYN=1, seq=x
服务器 -> 客户端: SYN=1, ACK=1, seq=y, ack=x+1
客户端 -> 服务器: ACK=1, seq=x+1, ack=y+1

TCP四次挥手

TCP四次挥手是终止连接的过程,确保双方数据完全传输完毕。具体步骤如下:

客户端发送FIN报文,序列号为u,进入FIN_WAIT_1状态。FIN报文表示请求断开连接。

服务器收到FIN报文后,回复ACK报文,确认号为u+1,进入CLOSE_WAIT状态。客户端收到ACK报文后进入FIN_WAIT_2状态。

服务器发送FIN报文,序列号为v,进入LAST_ACK状态。FIN报文表示同意断开连接。

客户端收到FIN报文后,回复ACK报文,确认号为v+1,进入TIME_WAIT状态。服务器收到ACK报文后关闭连接。客户端等待2MSL后也关闭连接。

客户端 -> 服务器: FIN=1, seq=u
服务器 -> 客户端: ACK=1, ack=u+1
服务器 -> 客户端: FIN=1, seq=v
客户端 -> 服务器: ACK=1, ack=v+1

常见问题

三次握手确保双方收发能力正常,避免资源浪费。四次挥手确保数据完全传输,防止数据丢失。TIME_WAIT状态防止最后一个ACK丢失导致服务器无法关闭。

tcp常规流程图:

TCP服务端核心函数解析

在Linux系统中,创建TCP服务端主要涉及以下关键函数,每个函数在通信流程中承担特定角色:

socket()

创建通信端点,返回文件描述符。参数指定协议族和套接字类型:

int socket(int domain, int type, int protocol);
  • domain: 通常为AF_INET(IPv4)或AF_INET6(IPv6)
  • typeSOCK_STREAM表示TCP协议
  • protocol: 通常为0,让系统自动选择

错误时会返回-1,并设置errno。典型用法:

int sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == -1) {perror("socket creation failed");exit(EXIT_FAILURE);
}

bind()

将套接字与特定IP地址和端口绑定:

int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
  • sockfd: socket()返回的文件描述符
  • addr: 指向包含地址信息的结构体(需转换为sockaddr*
  • addrlen: 地址结构体长度

地址结构体典型配置:

struct sockaddr_in servaddr;
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY); // 监听所有网卡
servaddr.sin_port = htons(8080); // 端口号

listen()

将套接字置为被动监听状态:

int listen(int sockfd, int backlog);
  • backlog: 已完成连接队列的最大长度,现代内核会自动调整这个值
  • 成功返回0,失败返回-1

典型调用:

if (listen(sockfd, SOMAXCONN) == -1) {perror("listen failed");close(sockfd);exit(EXIT_FAILURE);
}

accept()

接受客户端连接,返回新套接字描述符:

int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
  • addr: 用于存储客户端地址信息(可设为NULL)
  • addrlen: 输入时为addr缓冲区长度,输出时为实际长度
  • 成功返回非负文件描述符,失败返回-1

recv()/send()

进行数据收发操作:

ssize_t recv(int sockfd, void *buf, size_t len, int flags);
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
  • flags: 通常为0,可选MSG_WAITALL等标志
  • 返回值表示实际收发字节数,0表示对端关闭连接,-1表示错误

close()

关闭套接字描述符:

int close(int fd);

对于服务端程序,需要分别关闭监听套接字和连接套接字。

服务端示例:

TCP客户端函数解析

在Linux中,TCP客户端通常使用套接字API实现网络通信。以下是TCP客户端中常用函数的详细解析:

socket()

用于创建一个套接字,返回文件描述符。

int socket(int domain, int type, int protocol);
  • domain: 协议族,TCP通常使用AF_INET或AF_INET6
  • type: 套接字类型,TCP使用SOCK_STREAM
  • protocol: 通常为0,系统自动选择
  • 返回值:成功返回非负描述符,失败返回-1

connect()

用于与服务器建立连接。

int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
  • sockfd: socket()返回的描述符
  • addr: 指向包含服务器地址和端口的结构体
  • addrlen: 结构体长度
  • 返回值:成功返回0,失败返回-1

send()

用于向已连接的套接字发送数据。

ssize_t send(int sockfd, const void *buf, size_t len, int flags);
  • sockfd: 已连接的套接字描述符
  • buf: 发送数据缓冲区
  • len: 发送数据长度
  • flags: 通常为0
  • 返回值:成功返回发送的字节数,失败返回-1

recv()

用于从已连接的套接字接收数据。

ssize_t recv(int sockfd, void *buf, size_t len, int flags);
  • sockfd: 已连接的套接字描述符
  • buf: 接收数据缓冲区
  • len: 缓冲区长度
  • flags: 通常为0
  • 返回值:成功返回接收的字节数,0表示连接关闭,-1表示错误

close()

用于关闭套接字并释放资源。

int close(int fd);
  • fd: 要关闭的文件描述符
  • 返回值:成功返回0,失败返回-1

客户端示例:

TCP与UDP的对比

特性TCPUDP
连接方式面向连接无连接
可靠性可靠传输尽最大努力交付
数据顺序保证顺序不保证顺序
流量控制滑动窗口机制
头部开销20字节(最小)8字节
适用场景文件传输、Web浏览视频流、DNS查询

TCP粘包问题概述

在Linux网络编程中,TCP粘包是指发送方多次发送的数据被接收方一次性接收的现象,导致数据边界模糊。TCP是字节流协议,本身没有"包"的概念,数据被视为连续的字节流,因此需要应用层自行处理消息边界。

粘包产生原因

发送方和接收方缓冲区机制可能导致粘包:

  • 发送方Nagle算法合并小数据包
  • 接收方缓冲区数据堆积后一次性读取
  • 网络传输延迟导致多个数据包同时到达

解决方案

固定长度法 发送方和接收方约定固定长度的消息,不足部分填充。

特殊字符分隔法 使用特殊字符(如\n)作为消息边界,适用于文本协议。

长度前缀法 在消息头添加长度字段,接收方先读长度再读内容。最常用的可靠方案。

注意事项

  • UDP不存在粘包问题,因其保留消息边界
  • 异步/非阻塞IO场景需配合状态机处理半包情况
  • 网络字节序转换需使用htonl/ntohl等函数保证跨平台兼容性

相关文章:

  • C:\Users\中文名修改为英文名
  • JVM——如何打造一个类加载器?
  • 【Python训练营打卡】day44 @浙大疏锦行
  • simulink有无现成模块可以实现将三个分开的输入合并为一个[1*3]的行向量输出?
  • 矩形相交的面积 - 华为OD机试真题(JavaScript题解)
  • 筑牢企业网管域安全防线,守护数字核心——联软网管域安全建设解决方案
  • 在 CentOS 上安装 Docker 和 Docker Compose 并配置使用国内镜像源
  • 局域网空间内网络安全的实现分析
  • 基于责任链模式进行订单参数的校验
  • 相机Camera日志分析之二十五:高通相机Camx 基于预览1帧的process_capture_request四级日志分析详解
  • 搜广推特征数据变更灰度为什么实现很困难
  • PPT转图片拼贴工具 v4.3
  • 二叉树的遍历总结
  • 云原生思维重塑数字化基座:从理念到实践的深度剖析
  • 【图像处理入门】5. 形态学处理:腐蚀、膨胀与图像的形状雕琢
  • Android15 launcher3
  • javaweb -html -CSS
  • FPGA点亮ILI9488驱动的SPI+RGB接口LCD显示屏(一)
  • Declare规则
  • GDAL 内存数据集类型详解
  • 网站建设公司需要icp证/百度一下手机版
  • 做问卷的网站有那些/拼多多代运营公司十大排名
  • dw如何做网站界面/上海百度推广客服电话多少
  • 搬瓦工wordpress/网络优化工程师招聘信息
  • 淘宝 客要推广网站怎么做/比较正规的代运营
  • 桂林网站建设凡森网络/百度云账号登录