文章目录

  • 前言
  • 一,服务器端流程
    • 1-1 绑定协议
    • 1-2 绑定IP和端口
    • 1-3 监听客户端
    • 1-4 接收连接
    • 1-5 收发数据
    • 1-6 关闭连接
    • 1-7 服务端整体代码
  • 二,客户端流程
    • 2-1 指定地址和端口
    • 2-2 连接服务器
    • 2-3 发送消息
    • 2-4 客户端整体代码


前言

TCP 的通信过程就像两个人打电话:客户端先和服务端三次握手建立一条可靠的连接通道,之后数据会以字节流的形式在这条通道里双向传输,系统会负责把数据切片、编号、确认和重传,保证信息不丢失、不重复、按顺序送达,最后通过四次挥手优雅地断开连接。


连接流程大致如下图
在这里插入图片描述

一,服务器端流程

1-1 绑定协议

TCP通信也和UDP一样需要先创建套接字

int server_fd = socket(AF_INET, SOCK_STREAM, 0);

这里的SOCK_STREAM,说明套接字是用字节流的形式传递数据,也就是TCP通信


1-2 绑定IP和端口

sockaddr_in addr {};
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = INADDR_ANY; // 本机任意 IP
addr.sin_port = htons(12345); // 端口 12345
if (bind(server_fd, (sockaddr * ) & addr, sizeof(addr)) < 0) {perror("bind");return 1;
}

addr.sin_family = AF_INET;的意思就是,设置协议为IPv4,其它的不过多讲解就是绑定端口和将sockaddr_in转化为sockaddr

addr.sin_addr.s_addr = INADDR_ANY表示本机的客户端的任意IP都可以连接服务端


1-3 监听客户端

listen(server_fd, 5);
std::cout << "服务端启动,等待客户端连接..." << std::endl;

server_fd是我们socket创建的套接字,用于服务端得知是哪一个套接字要监听,所以必须传入 server_fd。没有 server_fd,内核就不知道“我要监听哪条网络通道”,就没法接受连接

这里的这个参数5表明:连接队列的最大长度,内核会维护一个队列,存放已到达但还没被 accept() 处理的客户端连接,这里写 5 表示最多允许排队 5 个连接请求。超过的请求可能会被拒绝。


1-4 接收连接

sockaddr_in client_addr{};
socklen_t len = sizeof(client_addr);
int client_fd = accept(server_fd, (sockaddr*)&client_addr, &len);

我们需要接收客户端的连接,这时会用到 sockaddr_in 来存储客户端的地址信息。accept() 会返回一个新的套接字 client_fd。因此服务器中会有 两种套接字:

  • server_fd:用于监听端口和接受客户端的连接请求。它可以同时管理多个客户端连接,但 不能直接用于数据通信。

  • client_fd:由 accept() 返回,用于和 特定客户端 进行通信。每个客户端连接都会对应一个独立的 client_fd,可以通过 read()write() 发送或接收数据。

简而言之:server_fd 用于建立连接,client_fd 用于通信,server_fd 可以服务多个客户端,而每个 client_fd 只对应一个客户端。


1-5 收发数据

char buffer[1024];
int n = read(client_fd, buffer, sizeof(buffer) - 1);
if (n > 0) {buffer[n] = '\0';std::cout << "收到客户端消息: " << buffer << std::endl;std::string reply = "Hello from server!";write(client_fd, reply.c_str(), reply.size());
}

先是读取数据,我们先定义一个buffer,将对应客户端的套接字对应的文件信息读取到buffer中,再使用write将数据发送到client_fd对应的套接字当中,这里其实没什么特别的,就是收数据/发数据


1-6 关闭连接

close(client_fd);
close(server_fd);

虽然只有一行,但是OS这里会让客户端和服务端发生四次挥手:

  • FIN(发送方): 服务端调用 close(client_fd)内核向客户端发送 FIN 报文,表示“我已经没有数据要发了”。

  • ACK(接收方): 客户端收到 FIN 后,回复 ACK 报文,确认收到,客户端仍然可以发送剩余数据。

  • FIN(接收方): 客户端发送完数据后,也调用 close(),向服务端发送 FIN 报文,表示“我也发送完了”。

  • ACK(发送方): 服务端收到 FIN 后,发送 ACK 报文 确认。连接真正关闭。


1-7 服务端整体代码

int main() {// 1. 创建套接字int server_fd = socket(AF_INET, SOCK_STREAM, 0);if (server_fd < 0) {perror("socket");return 1;}// 2. 绑定 IP 和端口sockaddr_in addr {};addr.sin_family = AF_INET;addr.sin_addr.s_addr = INADDR_ANY; // 本机任意 IPaddr.sin_port = htons(12345); // 端口 12345if (bind(server_fd, (sockaddr * ) & addr, sizeof(addr)) < 0) {perror("bind");return 1;}// 3. 监听listen(server_fd, 5);std::cout << "服务端启动,等待客户端连接..." << std::endl;// 4. 接受连接sockaddr_in client_addr {};socklen_t len = sizeof(client_addr);int client_fd = accept(server_fd, (sockaddr * ) & client_addr, & len);if (client_fd < 0) {perror("accept");return 1;}std::cout << "客户端已连接!" << std::endl;// 5. 收发数据char buffer[1024];int n = read(client_fd, buffer, sizeof(buffer) - 1);if (n > 0) {buffer[n] = '\0';std::cout << "收到客户端消息: " << buffer << std::endl;std::string reply = "Hello from server!";write(client_fd, reply.c_str(), reply.size());}// 6. 关闭连接close(client_fd);close(server_fd);return 0;
}

二,客户端流程

在客户端流程当中存在和服务端一样的流程,就是创建套接字,这里我们直接省略了。


2-1 指定地址和端口

sockaddr_in server_addr {};
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(12345);
inet_pton(AF_INET, "127.0.0.1", & server_addr.sin_addr); // 本地回环地址

这里我们创建的inet_pton的作用是把点分十进制的 IP 地址字符串转换成网络字节序的二进制形式

因为 socket 系统调用只能处理二进制的网络地址,而不能直接识别字符串形式的 IP,人类习惯用 "127.0.0.1" 这样的点分十进制 IP

内核底层在发送数据时,需要 32 位的二进制形式(网络字节序)来表示 IP 地址,inet_pton 就完成了 “人类可读 IP → 网络可用二进制 IP” 的转换,如果不做转换,connect()bind() 会因为地址无效而失败


2-2 连接服务器

我们通过connet来与服务端建立连接

if (connect(sock, (sockaddr * ) & server_addr, sizeof(server_addr)) < 0) {perror("connect");return 1;
}

这里没有什么很特别的,就是传递我们的地址端口接口体给服务端,然后服务端拿到结构体和客户端进行连接,并且客户端的sock套接字也和服务端的套接字对应的文件进行连接


2-3 发送消息

std::string msg = "Hello Server!";
write(sock, msg.c_str(), msg.size());
char buffer[1024];
int n = read(sock, buffer, sizeof(buffer) - 1);
if (n > 0) {buffer[n] = '\0';std::cout << "收到服务端回复: " << buffer << std::endl;
}

通过writeread发送和接收消息,也是很简单的代码


2-4 客户端整体代码

int main() {// 1. 创建套接字int sock = socket(AF_INET, SOCK_STREAM, 0);if (sock < 0) {perror("socket");return 1;}// 2. 指定服务端地址sockaddr_in server_addr {};server_addr.sin_family = AF_INET;server_addr.sin_port = htons(12345);inet_pton(AF_INET, "127.0.0.1", & server_addr.sin_addr); // 本地回环地址// 3. 连接服务器if (connect(sock, (sockaddr * ) & server_addr, sizeof(server_addr)) < 0) {perror("connect");return 1;}std::cout << "已连接服务器!" << std::endl;// 4. 发送消息std::string msg = "Hello Server!";write(sock, msg.c_str(), msg.size());// 5. 接收回复char buffer[1024];int n = read(sock, buffer, sizeof(buffer) - 1);if (n > 0) {buffer[n] = '\0';std::cout << "收到服务端回复: " << buffer << std::endl;}// 6. 关闭close(sock);return 0;
}

演示结果:
服务端

root@hcss-ecs-f59a:/gch/code/HaoHao/learn3/day6# ./server
服务端启动,等待客户端连接...
客户端已连接!
收到客户端消息: Hello Server!

客户端

root@hcss-ecs-f59a:/gch/code/HaoHao/learn3/day6# ./client
已连接服务器!
收到服务端回复: Hello from server!

本博客中只是做了一个简单的服务端和客户端的通信,在实际项目当中,这种通信代码还是前篇一律的,所以我就采用了分布式讲解

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/news/923664.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/923664.shtml
英文地址,请注明出处:http://en.pswp.cn/news/923664.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

飞书智能查询机器人搭建说明文档

飞书智能查询机器人搭建说明文档 一、使用手册 1. 创建飞书机器人应用 如果仅需对接已有机器人应用则可跳过该步骤&#xff08;建议各业务部门独立使用各自的机器人应用&#xff09;。在飞书开发者后台中创建企业自建应用&#xff0c;添加机器人应用能力并申请对应的身份权限…

蓝色系列包装行业网站 适合企业站,带手机版自适应

内容目录一、详细介绍二、效果展示1.部分代码2.效果图展示三、学习资料下载一、详细介绍 蓝色通用企业网站是基于SDCMS四合一企业网站管理系统开发的模板&#xff0c;适合企业站&#xff0c;带手机版。 四网合一企业网站管理系统是一个以PHPMySQL/Sqlite进行开发的四网合一网…

【大模型:知识图谱】--6.Neo4j DeskTop安装+使用

上一期讲了图知识库的安装&#xff0c; 【图数据库】--Neo4j 安装_neo4j安装-CSDN博客 现在来看看可视化管理程序&#xff1a;Neo4j DeskTop的安装. 需要先安装java环境&#xff0c;具体看上面 目录 1.Neo4j DeskTop版下载 2.Neo4j DeskTop版安装 3.Neo4j DeskTop版使用 …

Python爬虫实战——使用NetNut网页解锁器获取亚马逊电商数据

文章目录一、电商数据的作用1.1 支撑科学决策&#xff0c;降低试错成本1.2 提升运营效率&#xff0c;实现降本增效1.3 深化用户理解&#xff0c;驱动个性化服务1.4 监测竞品动态&#xff0c;制定差异化策略1.5 驱动产品创新&#xff0c;满足用户需求二、爬取目标三、环境准备四…

超越NAT:如何构建高效、安全的内网穿透隧道

在敏捷开发和分布式协作成为主流的今天&#xff0c;开发者需要一个能够将本地开发环境瞬间暴露给公网的能力&#xff0c;以便进行演示、联调或处理回调。传统方案如配置路由器端口映射或部署VPN&#xff0c;不仅繁琐且存在安全风险。内网穿透技术&#xff0c;特别是以 ngrok、Z…

第二十三章 ESP32S3 RTC 实验

本章介绍 ESP32-S3 实时时钟&#xff08;RTC&#xff09;的使用&#xff0c;实时时钟能为系统提供一个准确的时间&#xff0c;即时系统复位或主电源断电&#xff0c; RTC 依然能够运行&#xff0c;因此 RTC 也经常用于各种低功耗场景。通过本章的学习&#xff0c;将学习到 RTC …

Java 轻松实现 Markdown 转 Word、PDF、HTML

在软件开发和技术写作领域&#xff0c;Markdown 已成为一种被广泛使用的轻量级标记语言。它的语法简洁&#xff0c;书写效率高&#xff0c;非常适合快速记录笔记、撰写技术文档或博客文章。但在实际应用中&#xff0c;Markdown 文件往往需要被转换为更通用的格式&#xff0c;例…

Kafka系列之:Kafka broker does not support the ‘MetadataRequest_v0‘ Kafka protocol.

Kafka系列之:Kafka broker does not support the MetadataRequest_v0 Kafka protocol. 一、完整报错 二、错误原因 三、解决方法 一、完整报错 kafka.errors.IncompatibleBrokerVersion: IncompatibleBrokerVersion: Kafka broker does not support the ‘MetadataRequest_v0’…

开源AI红队工具“Red AI Range“助力发现、分析与缓解AI系统漏洞

开源AI红队平台Red AI Range&#xff08;RAR&#xff09;正在改变安全专业人员评估和强化AI系统的方式。该平台通过模拟真实攻击场景&#xff0c;利用容器化架构和自动化工具&#xff0c;简化了AI特有漏洞的发现、分析和缓解流程。**核心功能** 1. 武器库/目标按钮可快速启动…

SQL 数据库简介

SQL&#xff08;Structured Query Language&#xff09;是一种用于管理和操作关系型数据库的标准语言。关系型数据库以表格形式存储数据&#xff0c;并通过行和列的结构化方式组织信息。SQL 提供了一套强大的命令&#xff0c;用于查询、插入、更新和删除数据&#xff0c;以及管…

SpringBoot4与Spring7发布:云原生深度进化

Spring Boot 4和Spring Framework 7带来基础要求升级、模块化改进、API版本化、声明式HTTP客户端、弹性注解等重大特性&#xff0c;标志着Java开发生态向云原生时代的深度进化。 近日&#xff0c;Spring生态迎来了自2022年以来最具里程碑意义的更新——Spring Boot 4和Spring …

基于Spring Boot与Micrometer的系统参数监控指南

如何为你的Spring Boot应用装上一个功能强大的监控仪表盘在现代微服务架构中&#xff0c;系统监控已成为保障应用稳定性的关键环节。通过有效的监控&#xff0c;我们可以实时了解应用的运行状态&#xff0c;及时发现并解决性能问题。本文将介绍如何使用Micrometer及其注册表&am…

【运维】-- 前端会话回放与产品分析平台之 openreplay

目录 OpenReplay 项目分析 1、项目概览 2、关键特性 3、代码结构&#xff08;Monorepo&#xff09; 4、技术栈与语言占比 5、部署与交付 6、社区与支持 7、版本与活跃度&#xff08;截至仓库页面所示&#xff09; 8、适用场景 9、优势与注意事项 10、落地建议&#…

NineData社区版 V4.5.0 正式发布!运维中心新增细粒度任务权限管理,新增MySQL至Greenplum全链路复制对比

NineData 社区版 V4.5.0 正式发布&#xff01;在数据复制方面&#xff0c;新增 MySQL 至 Greenplum 全链路复制对比&#xff0c;并优化全局 DDL 管控、MySQL/PostgreSQL/MongoDB 同构性能。在数据库 DevOps 方面&#xff0c;新增支持 AWS RDS 全系列及阿里云 PolarDB&#xff0…

discuz所有下载版本和升级工具

下载版本: Discuz! 每日构建版下载 - DiscuzX 3.x Daily Build Download Site SC是简体中文 TC是繁体中文 可能你需要其他版本: Discuz!官方网站 - 开放、连接、共赢 下载简体中文就好。 升级工具: 升级程序下载地址 https://gitee.com/oldhuhu/DiscuzX34235.git(…

【开题答辩全过程】以 “红色枣庄”旅游网站为例,包含答辩的问题和答案

个人简介一名14年经验的资深毕设内行人&#xff0c;语言擅长Java、php、微信小程序、Python、Golang、安卓Android等开发项目包括大数据、深度学习、网站、小程序、安卓、算法。平常会做一些项目定制化开发、代码讲解、答辩教学、文档编写、也懂一些降重方面的技巧。感谢大家的…

【LeetCode】2785. 将字符串中的元音字母排序

题目描述 题目链接 问题分析 这道体的思路非常简单和好理解&#xff0c;找出字符串中的元音字符&#xff0c;然后按照ASSIC值进行排序&#xff0c;然后插入回对应的位置&#xff0c;解题步骤为&#xff1a; 使用一个set&#xff08;可以快速查找的容器&#xff09;&#x…

3 步发 10 亿邮件,这个 GitHub 开源项目牛逼。

你是否要经常批量发邮件&#xff1f;无论是向客户推送最新资讯、产品营销&#xff0c;还是发送日常常规通知类邮件。使用第三方邮件服务平台不仅成本高昂&#xff0c;功能限制多&#xff0c;而且可能无法保证隐私和安全。现在&#xff0c;有一个完全开源、能自己部署的解决方案…

【计算机网络】DNS 解析 DNS 污染

1. DNS 解析&#xff08;工作流程、参与方与缓存&#xff09; DNS 的目标&#xff1a;把人类可读的域名&#xff08;如 www.example.com&#xff09;映射为 IP 地址&#xff08;如 93.184.216.34&#xff09;。 典型解析流程&#xff08;递归解析器 迭代查询&#xff09;&…

用住宿楼模型彻底理解Kubernetes架构(运行原理视角)

导读&#xff1a;从楼宇建设到租客入住的全流程想象我们正在建设一栋巨型智能住宿楼&#xff0c;从基础设施搭建到租客入住管理&#xff0c;每个环节都对应Kubernetes的组件和概念。本文将按运行原理的先后顺序&#xff0c;系统解析Kubernetes的23个核心组件与基本概念。把 Kub…