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

网络:tcp

服务器//客户端模型(常见模型分析)

1.c//s        服务器·(c)专用        HTTP协议,自定义协议,标准协议。      资源大部分在cli客户端

不受协议影响,较复杂。

2.b//s        服务器(c)通用        HTTP协议。             资源大部分服务器发送至客户端(ser->cli)

受到HTTP协议影响,功能较简单。

3.p2p        在线直播,文件下载。

TCP:传输控制协议。

流式套接字:数据和数据之间连续;先发先收;数据连续;可靠传输。

TCP传输,当链路搭建后,会维持通道。建立连接过程包含“三次握手,四次挥手”。全双工通信。

TCP传输可靠原因:应答,超时重传。(只要发送就会返回应答。已发送未应答,数据会重发,等待应答信号。)

“三次握手,四次挥手”流程图

SYN:建立连接;FIN:释放连接。

TCP三次握手 (Three-way Handshake)

目的: 建立一条TCP连接。
过程:

  1. 第一次握手 (SYN): 客户端先向服务器发送一个SYN包(SYN=1),并随机生成一个序列号(seq=x),进入SYN_SENT状态。

  2. 第二次握手 (SYN+ACK): 服务器收到SYN包后,必须确认客户端的SYN。同时自己也发送一个SYN包(SYN=1)。因此会发送一个SYN-ACK包(SYN=1, ACK=1),并确认号ack=x+1,同时自己也随机生成一个序列号seq=y,进入SYN_RCVD状态。

  3. 第三次握手 (ACK): 客户端收到服务器的SYN-ACK包后,向服务器发送一个确认包ACK(ACK=1),确认号ack=y+1,序列号seq=x+1。完成后,客户端和服务器都进入ESTABLISHED状态,连接建立成功。


TCP四次挥手 (Four-way Wavehand)

目的: 终止一条TCP连接。
过程:

  1. 第一次挥手 (FIN): 主动关闭方(可以是客户端或服务器)发送一个FIN包(FIN=1),并指定一个序列号(seq=u),进入FIN_WAIT_1状态。

  2. 第二次挥手 (ACK): 被动关闭方收到FIN包后,发送一个ACK包(ACK=1)作为确认,确认号为ack=u+1,并带上自己的序列号seq=v。此时被动关闭方进入CLOSE_WAIT状态,主动关闭方收到这个ACK后进入FIN_WAIT_2状态。

  3. 第三次挥手 (FIN): 被动关闭方处理完所有数据后,也发送一个FIN包(FIN=1),并指定一个序列号(seq=w),进入LAST_ACK状态。

  4. 第四次挥手 (ACK): 主动关闭方收到FIN后,发送一个ACK包(ACK=1)作为确认,确认号为ack=w+1,序列号为seq=u+1。然后进入TIME_WAIT状态,等待一段时间(2MSL)后彻底关闭。被动关闭方收到这个ACK后,立即关闭连接。

TCP协议->流程(函数)

服务器端:tcp ser->(建立)socket->(绑定)bind->(监听)listen->(通信)accept->(接收)recv->(发送)send

客户端:tcp cli->(建立)socket->(主动发起连接->三次握手)connect->(发送)send->(接收)recv

TCP/UDP,缓冲区64k。TCP缓冲区是双缓冲区。收发都是64k,不干扰。UDP是单个缓冲区64k。

数据的粘包(发送方发送数据,接收方无法解析数据。)解决办法:

1.设置边界。

2.固定大小。

3.自定义协议。

具体例子:代码能运行成功,就是图片加载不出来。

服务端:

typedef struct sockaddr*(SA);
int	main(int argc, char **argv)
{//监听套接字int listfd=socket(AF_INET,SOCK_STREAM,0);if (-1==listfd){perror("listfd err...");return 1;}//man 7 ipstruct sockaddr_in ser,cli;//清空bzero(&ser,sizeof(ser));bzero(&cli, sizeof(cli));ser.sin_family=AF_INET;ser.sin_port =htons(50000);//INADDR_ANY代表网卡信息ser.sin_addr.s_addr=INADDR_ANY;int ret= bind(listfd,(SA)&ser,sizeof(ser));if (-1==ret){perror("ret err...");return 1;}//listen中3的原因——服务器三次握手的排队数,不是连接客户端个数。listen(listfd, 3);socklen_t len = sizeof(cli);//通信套接字int conn = accept(listfd, (SA)&cli, &len);if(-1==conn){perror("conn err...");return 1;}int fd = open("2.png",O_WRONLY|O_CREAT|O_TRUNC,0666);if (-1==fd){perror("fd err...");return 1;}time_t tm;while (1){char buf[1024]={0};int ret= recv(conn, buf, sizeof(buf), 0);if (ret<=0){break;}time(&tm);write(fd, buf, ret);}close(listfd);close(conn);close(fd);//system("pause");return 0;
}

客户端:

typedef struct sockaddr*(SA);
int	main(int argc, char **argv)
{//监听套接字int conn=socket(AF_INET,SOCK_STREAM,0);if (-1==conn){perror("conn err...");return 1;}//man 7 ipstruct sockaddr_in ser;//清空bzero(&ser,sizeof(ser));ser.sin_family=AF_INET;ser.sin_port =htons(50000);//INADDR_ANY代表网卡信息ser.sin_addr.s_addr=INADDR_ANY;int ret= connect(conn,(SA)&ser,sizeof(ser));if (-1==ret){perror("ret err...");return 1;}int fd = open("test.png", O_RDONLY);if (-1 == fd){perror("open error\n");return 1;}while (1){char buf[1024]={0};bzero(buf, sizeof(buf));int ret = read(fd, buf, sizeof(buf));if (ret <= 0){break;}send(conn, buf, ret, 0);bzero(buf, sizeof(buf));recv(conn, buf, sizeof(buf), 0);// printf("ser:%s\n",buf); }close(conn);close(fd);//system("pause");return 0;
}

解决方案

1. 使用协议头

c

复制下载

// 发送文件前先发送文件信息
struct file_info {uint32_t file_size;uint32_t file_name_len;// 后续跟文件名和数据
};

2. 使用固定长度的结束标记

c

复制下载

// 使用独特的结束标记,如8字节的特殊序列
const char END_MARKER[8] = {0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xAA, 0x55, 0xCC};

3. 使用文件大小作为传输结束条件

c

复制下载

// 客户端先发送文件大小
uint32_t file_size = get_file_size("test.png");
send(conn, &file_size, sizeof(file_size), 0);// 服务器端根据文件大小接收
uint32_t total_received = 0;
while (total_received < file_size)
{int ret = recv(conn, buf, sizeof(buf), 0);write(fd, buf, ret);total_received += ret;
}
http://www.xdnf.cn/news/20010.html

相关文章:

  • 关于稳定币的一些问答
  • 封装一个redis获取并解析数据的工具类
  • FPGA学习笔记——SDR SDRAM简介
  • 【golang长途旅行第37站】Redis连接池
  • OCR 发票识别与验真接口:助力电子化发票新时代
  • 融云:当我们谈论 AI 重构业务时,我们到底在谈论什么
  • 【Android】SharedPreferences轻量级持久化存储
  • 【题解】洛谷P1776 宝物筛选 [单调队列优化多重背包]
  • C++----模板特化以及模板声明与定义分离问题
  • AT32网线拔插下,modbus tcp断线重连
  • Linux awk命令完全指南:从原理到实战,搞定文本处理难题
  • 【AI】人工智能 传统和现代 架构和算法的演变历史
  • windows安装谷歌浏览器地址
  • TypeScript `infer` 关键字详解(从概念到实战)
  • AGV 搬运小车路径规划:从地图构建到路径决策的技术全解析
  • 打通 Flutter 与原生状态管理:Android ViewModel 的运用
  • SpringBoot+PDF.js实现按需分片加载(包含可运行样例源码)
  • C++小游戏
  • 腾讯开源HunyuanWorld-Voyager突破性原生3D重建与视频扩散框架
  • 计算机大数据毕业设计选题:基于Spark+hadoop的全球香水市场趋势分析系统
  • 优思学院|5个为什么(5 Whys)分析法一文讲清楚
  • AI编写自动点击器 - 毫秒级精准鼠标连点器
  • kafka:【1】概念关系梳理
  • kvm 虚拟机如何安装 qemu-guest-agent
  • kali_linux
  • 【Linux】线程封装
  • 【FastDDS】Layer DDS之Domain ( 04-DomainParticipantFactory)
  • 采用基于模型的方法实现车辆SOA威胁分析自动化
  • wpf 自定义密码文本框,并且可以双向绑定
  • 吱吱企业通讯软件以安全为核心,构建高效沟通与协作一体化平台