【计算机网络】TCP实战
其实有了UDP的基础,TCP不管怎么说学习起来都还是比较舒服的,至少是比直接就学习TCP的感觉好。
这篇文章最多就是介绍一下起手式,如果想带业务的话和UDP那篇是完全一样的,就不进行演示了。
总的来说还是很简单的。
目录
- Echo
- 服务端起手式
- 服务端LOOP
- 客户端起手
- 客户端LOOP
- 验证
- 改进
- 方案一
- 方案二
- 验证
Echo
我们还是从最简单的不带业务的Echo开始。
服务端起手式
服务器起手式
首先要说明的一点是,TCP是面向字节流,有连接。
而UDP创建好套接字后不管连接,直接recvfrom,sendto就可以发送。
在TCP编码中会体现出有连接的特点,面向字节流会在理论中提及,代码中实践。
创建套接字
首先与UDP不同的是,UDP的第二个参数是SOCK_DGRAM。
_listenfd = ::socket(AF_INET, SOCK_STREAM, 0);
关于这两个参数不同含义更详细的放在下图中了。

另外,这次使用listenfd接收,以前我们获得的就是sockfd,直接使用这个描述符进行收发,那么叫listenfd肯定是有特别用意。
进行bind
bind没什么好说的,仍旧是要注意填参问题。
int n = ::bind(_listenfd, (struct sockaddr *)&local, len);
进入listen状态

从这里就可以看到面向连接的痕迹了。
那么什么叫listen状态?
我们举一个小例子:
UDP就是无人售货店,不许用老板看店即可买东西。
但是TCP就是有人售货店,需要老板在才可以买东西,而TCP就是那个有人售货店,listen就是设置为老板模式,这样就可以接客了。
第一个参数就是你得到的listenfd。
第二个参数是连接队列长度,这个值我们暂时先不用管,一般默认设置为4, 8, 16即可,不需要太大。
n = ::listen(_listenfd, gbacklog);
服务端LOOP
accept
来了新的连接我们就要去accept了
换句话说就是在有人售货店中现在如果来客人了老板就需要去接客。
int sockfd = ::accept(_listenfd, (sockaddr *)&peer, &len);
参数是输出型参数,来一个连接就可以获得这个连接的基本信息。
但是要注意填参时一定要正确填参,虽然addrlen是一个输出型参数,但仍然需要正确初始化,不能不初始化。
我就犯了这个错误,导致有时错误(accept或者connect错误,connect在客户端会提到),甚至搞的我以为这是tcp特性…
但是我们注意到返回值是一个文件描述符!?那么他是什么?与listenfd有何区别?
我们举一个例子进行理解:

上图可以形象的帮助理解返回值。
其中饭店 = 服务器
客户 = 新连接
揽客员 = listenfd(socket返回值)
服务员 = sockfd (accept返回值)
listenfd不直接提供服务,sockfd才直接提供服务!
所以在TCP服务端我们一般将socket返回值叫做监听套接字。
没有连接时就会陷入阻塞状态,accept失败返回-1(这里可以理解为揽客员都把路人拉到店里面,但是路人又临时有事离开了,导致拉客失败~)。
下段代码是TCP的框架代码,与UDP有很大的不同。
void Loop()
{_isrunning = true;while (_isrunning){sockaddr_in peer;socklen_t len = sizeof(peer);int sockfd = ::accept(_listenfd, (sockaddr *)&peer, &len);if (sockfd < 0){continue;}// version 0 :提供长服务。service(sockfd);}_isrunning = false;
}
与UDP有很大的不同:
每一次循环都对应着一个新连接,我们随后要对这个新连接进行长服务;
而UDP是不管来的是谁,都统一处理。
读写操作
我们在长服务中进行读写操作。
因为我们是面向字节流,而管道、文件也都是流。
且Linux下一切皆文件,管道、文件都是文件,所以都是可以用文件操作read,write进行读写,所以这里也可以使用文件操作!
void service(int sockfd)
{// 长服务while (true){char inbuffer[1024];int n = read(sockfd, inbuffer, sizeof(inbuffer) - 1);if (n > 0){inbuffer[n] = 0;int m = write(sockfd, inbuffer, n);if (m < 0){break;}}else if (n == 0){break;}else{break;}}::close(sockfd);
}
但是这里有一个细节要注意:read的返回值>0是表示读到的字节数(无\0),==0时表示读到文件结尾,在这里表示客户端结束。
就想吃在管道那里,写端管了,读端读出的自然都是0了。
客户端起手
socket
int sockfd = ::socket(AF_INET, SOCK_STREAM, 0);
注意客户端仍旧是用socket的返回值进行通信。
connect
同样,客户端还是不用bind,在UDP那是sendto时OS进行绑定,而在这就是connect时帮我们自动绑定。
sockaddr_in peer;
memset(&peer, 0, sizeof(peer));
inet_pton(AF_INET, ip.c_str(), &peer.sin_addr);
peer.sin_port = htons(port);
peer.sin_family = AF_INET;
int n = ::connect(sockfd, (sockaddr *)&peer, sizeof(peer));
客户端LOOP
这里没啥好说的,就是普通的write + read。
但是要注意:由于是面向字节流,所以这里的处理是有问题的!具体如何操作请看用户自定义协议与序列化
while (true)
{std::cout << "Please enter#";std::string line;getline(std::cin, line);n = write(sockfd, line.c_str(), line.size());if (n < 0){break;}char inbuffer[1024];n = read(sockfd, inbuffer, sizeof(inbuffer) - 1);if (n > 0){inbuffer[n] = 0;std::cout << inbuffer << std::endl; }
}
完整代码链接
验证

但是当我们多开一个客户端就会发现:一个服务端只能服务一个客户端。
原因在于我们当前是串行,必须等当前客户端退出才能accept下一个客户端,并没有处理并发客户端的能力。
所以改进就来了
改进
方案一
多进程方案。
我们知道子进程是会继承父进程的代码和数据的,同样的文件描述符表也会继承,因此我们就可以利用这个特点让子进程去执行代码和数据。

首先我们fork之后就要将不需要的文件描述符关闭
对于子进程来说,是怕误操作;
对于父进程来说,是为了防止文件描述符泄露,因为进程具有独立性,当子进程继承了后,就与父进程相互不影响了。若是父进程不关闭,一直申请fd却步关闭那么就造成了资源泄露。
但是注意,由于父进程要进行等待,所以此时仍然是串行。
想要解决有两种方法
- 由于子进程结束时会发送SIGCHLD信号,于是进行信号忽略
signal(SIGCHLD, SIG_IGN)。另外这也是最佳方案。 - 下段代码所示:我们进行再次fork,并让子进程退出,所以此时孙子进程成为了孤儿进程,孤儿进程的父进程是OS,结束归OS管,完美的利用了OS的特性。
pid_t pid = fork();
if (pid == 0)
{if (fork() > 0) exit(0);// 子进程关闭不需要的fd,防止误操作。::close(_listenfd);service(sockfd, inetaddr);exit(0);
}
waitpid(pid, nullptr, 0);
// 父进程关闭不需要的fd,防止内存泄漏。
::close(sockfd);
方案二
多线程
我们创建一个新线程,让新线程去执行service即可。
验证
此时同时启动两个客户端也可以完美的进行并发了。

相关文章:
【计算机网络】TCP实战
其实有了UDP的基础,TCP不管怎么说学习起来都还是比较舒服的,至少是比直接就学习TCP的感觉好。 这篇文章最多就是介绍一下起手式,如果想带业务的话和UDP那篇是完全一样的,就不进行演示了。 总的来说还是很简单的。 目录 Echo服务端…...
使用Python制作贪吃蛇小游戏
引言 贪吃蛇游戏是一款经典的电子游戏,玩家通过控制一条不断增长的蛇在格子内移动,并吃掉随机出现的食物来获得分数。随着分数的增加,蛇的身体也会越来越长,游戏的难度也随之提升。在本文中,我们将详细介绍如何使用Py…...
线程的退出
方式1 pthread_exit Void pthread_exit (void *retval) 功能: 结束调用的线程 参数: retval //退出状态值 //需要传的是,退出状态值的地址 注意: 1.pthread_exit 本身表示结束线程 如果用在main函数中 表示结束主线程…...
【AI 绘画】Q版人物定制生成
AI 绘画-PulID手办定制 1. 效果展示 本次测试主要结果展示如下: 牛仔风 古风 2. 基本原理 PuLID是一种类似于 ip-adapter 的恢复面部特征的方法。它同时使用 insightface 嵌入和 CLIP 嵌入,类似于 ip-adapter faceid plus 模型所做的。但是,在将图像传递给 CLIP 之前,还…...
Python爬虫——爬取某网站的视频
爬取视频 本次爬取,还是运用的是requests方法 首先进入bilibili官网中,选取你想要爬取的视频,进入视频播放页面,按F12,将网络中的名称栏向上拉找到第一个并点击,可以在标头中,找到后续我们想要…...
Android逆向题解攻防世界-easy-apk
Jeb反编译apk 题目比较简单,就是一个改了码表的base64编码。 protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);this.setContentView(0x7F04001B); // layout:activity_main((Button)this.findViewById(0x7F0B0076)).set…...
Linux系统使用Typecho搭建个人网站并一键发布公网远程管理本地站点
文章目录 前言1. 安装环境2. 下载Typecho3. 创建站点4. 访问Typecho5. 安装cpolar6. 远程访问Typecho7. 固定远程访问地址8. 配置typecho 💡 推荐 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大…...
机器学习速成第三集——无监督学习之聚类(理论部分)!
目录 聚类的定义和原理 常见的聚类算法 应用场景 总结 无监督学习中聚类算法的最新进展是什么? K-Means聚类算法在处理大规模数据集时的性能优化方法有哪些? 并行计算模型: 多核处理器优化: 分层抽样: 特征缩…...
【机器学习】CNN的基本架构模块
🌈个人主页: 鑫宝Code 🔥热门专栏: 闲话杂谈| 炫酷HTML | JavaScript基础 💫个人格言: "如无必要,勿增实体" 文章目录 CNN的基本架构模块1. 引言2. 卷积层2.1 基本原理2.2 卷积层的特性2.3 卷积层的超…...
第八节AWK报告生成器(2)
3,1,2 printf 语法: printf("format\n", [arguments])格式说明 format是一个用来描述输出格式的字符串,format格式的指示符都以%开头,后跟一个字符,如下: format含义%c显示字符的asicll%d,%i十进制整数%e,%E科学计数法显示数值…...
Linux 进程间通信之管道
个人主页:仍有未知等待探索-CSDN博客 专题分栏: Linux 目录 一、通信 1、进程为什么要通信? 1.数据的类型 2.父进程和子进程算通信吗? 2、进程如何通信? 3、进程通信的常见方式? 二、管道 1、概念…...
IDEA 无法启动,点击之后没有任何提示或者界面
当你尝试通过双击或以管理员身份启动程序时,均未能成功,且未收到任何提示信息或界面反馈,这确实令人困扰。为了诊断问题并获取有用的错误信息,你可以按照以下步骤操作: 1. 启用并查看错误信息 首先,你需要…...
ctf 堆栈结构
CTF(Capture The Flag)竞赛中,理解堆栈结构对于解决涉及二进制分析、逆向工程和利用开发的挑战至关重要。堆栈是在程序执行过程中用于临时存储数据和管理函数调用的关键数据结构。以下是堆栈结构的基本概念及其在CTF竞赛中的应用:…...
sqlserver的openquery配置
1.命令Demo ---openquery--开启Ad Hoc Distributed Queries组件,在sql查询编辑器中执行如下语句exec sp_configure show advanced options,1reconfigureexec sp_configure Ad Hoc Distributed Queries,1reconfigure--关闭Ad Hoc Distributed Queries组件࿰…...
Spring boot logback日志框架加载初始化源码
##LoggingApplicationListener监听 Overridepublic void onApplicationEvent(ApplicationEvent event) {if (event instanceof ApplicationStartingEvent) {onApplicationStartingEvent((ApplicationStartingEvent) event);}else if (event instanceof ApplicationEnvironment…...
qt-11基本对话框(消息框)
基本对话框--消息框 msgboxdlg.hmsgboxdlg.cppmain.cpp运行图QustionMsgInFormationMsgWarningMsgCriticalMsgAboutMsgAboutAtMsg自定义 msgboxdlg.h #ifndef MSGBOXDLG_H #define MSGBOXDLG_H#include <QDialog> #include <QLabel> #include <QPushButton>…...
Windows11下wsl闪退的解决
wsl闪退 1. 原因分析 解释:WSL(Windows Subsystem for Linux)闪退通常指的是在Windows操作系统中运行的Linux环境突然关闭。这可能是由于多种原因造成的,包括系统资源不足、WSL配置问题、兼容性问题或者是Linux内核的问题。&…...
通过调整JVM的默认内存配置来解决内存溢出(OutOfMemoryError)或栈溢出(StackOverflowError)等错误
文章目录 引言I 调整JVM的默认堆内存配置java命令启动jar包Tomcat服务器部署java应用引言 问题: org.springframework.web.util.estedServletException: Handlerdispatch failed: nested exception isjava.lang.0utOfMemoryError: Java heap space原因分析: 查询查询平台所…...
RCE---eval长度限制绕过技巧
目录 题目源码 方法一:命令执行的利用 方法二:file_put_contents(本地文件包含的利用) 方法三:usort(…$_GET); 题目源码 <?php $param $_REQUEST[param]; if(strlen($param)<17 && stripos($par…...
C++11标准模板(STL)- 算法库 - 类似 std::accumulate,但不依序执行 -(std::reduce)
算法库 算法库提供大量用途的函数(例如查找、排序、计数、操作),它们在元素范围上操作。注意范围定义为 [first, last) ,其中 last 指代要查询或修改的最后元素的后一个元素。 类似 std::accumulate,但不依序执行 std…...
R语言AI模型部署方案:精准离线运行详解
R语言AI模型部署方案:精准离线运行详解 一、项目概述 本文将构建一个完整的R语言AI部署解决方案,实现鸢尾花分类模型的训练、保存、离线部署和预测功能。核心特点: 100%离线运行能力自包含环境依赖生产级错误处理跨平台兼容性模型版本管理# 文件结构说明 Iris_AI_Deployme…...
AspectJ 在 Android 中的完整使用指南
一、环境配置(Gradle 7.0 适配) 1. 项目级 build.gradle // 注意:沪江插件已停更,推荐官方兼容方案 buildscript {dependencies {classpath org.aspectj:aspectjtools:1.9.9.1 // AspectJ 工具} } 2. 模块级 build.gradle plu…...
C#学习第29天:表达式树(Expression Trees)
目录 什么是表达式树? 核心概念 1.表达式树的构建 2. 表达式树与Lambda表达式 3.解析和访问表达式树 4.动态条件查询 表达式树的优势 1.动态构建查询 2.LINQ 提供程序支持: 3.性能优化 4.元数据处理 5.代码转换和重写 适用场景 代码复杂性…...
比较数据迁移后MySQL数据库和OceanBase数据仓库中的表
设计一个MySQL数据库和OceanBase数据仓库的表数据比较的详细程序流程,两张表是相同的结构,都有整型主键id字段,需要每次从数据库分批取得2000条数据,用于比较,比较操作的同时可以再取2000条数据,等上一次比较完成之后,开始比较,直到比较完所有的数据。比较操作需要比较…...
什么是VR全景技术
VR全景技术,全称为虚拟现实全景技术,是通过计算机图像模拟生成三维空间中的虚拟世界,使用户能够在该虚拟世界中进行全方位、无死角的观察和交互的技术。VR全景技术模拟人在真实空间中的视觉体验,结合图文、3D、音视频等多媒体元素…...
Spring Security 认证流程——补充
一、认证流程概述 Spring Security 的认证流程基于 过滤器链(Filter Chain),核心组件包括 UsernamePasswordAuthenticationFilter、AuthenticationManager、UserDetailsService 等。整个流程可分为以下步骤: 用户提交登录请求拦…...
一些实用的chrome扩展0x01
简介 浏览器扩展程序有助于自动化任务、查找隐藏的漏洞、隐藏自身痕迹。以下列出了一些必备扩展程序,无论是测试应用程序、搜寻漏洞还是收集情报,它们都能提升工作流程。 FoxyProxy 代理管理工具,此扩展简化了使用代理(如 Burp…...
Appium下载安装配置保姆教程(图文详解)
目录 一、Appium软件介绍 1.特点 2.工作原理 3.应用场景 二、环境准备 安装 Node.js 安装 Appium 安装 JDK 安装 Android SDK 安装Python及依赖包 三、安装教程 1.Node.js安装 1.1.下载Node 1.2.安装程序 1.3.配置npm仓储和缓存 1.4. 配置环境 1.5.测试Node.j…...
【Ftrace 专栏】Ftrace 参考博文
ftrace、perf、bcc、bpftrace、ply、simple_perf的使用Ftrace 基本用法Linux 利用 ftrace 分析内核调用如何利用ftrace精确跟踪特定进程调度信息使用 ftrace 进行追踪延迟Linux-培训笔记-ftracehttps://www.kernel.org/doc/html/v4.18/trace/events.htmlhttps://blog.csdn.net/…...
如何做好一份技术文档?从规划到实践的完整指南
如何做好一份技术文档?从规划到实践的完整指南 🌟 嗨,我是IRpickstars! 🌌 总有一行代码,能点亮万千星辰。 🔍 在技术的宇宙中,我愿做永不停歇的探索者。 ✨ 用代码丈量世界&…...
