【Linux】TCP网络编程
目录
V1_Echo_Server
V2_Echo_Server多进程版本
V3_Echo_Server多线程版本
V3-1_多线程远程命令执行
V4_Echo_Server线程池版本
V1_Echo_Server
TcpServer的上层调用如下,和UdpServer几乎一样:
而在InitServer中,大部分也和UDP那里一样,不同的是使用socket时第二个参数是SOCK_STREAM。
除了创建socket和bind外,还有第三步,因为tcp是面向连接的,tcp需要未来不断地能够做到获取连接,需要将server套接字设为listen状态,以便随时等待被获取连接,
其中backlog一般设为较小的数字,比如4、8等。
此时,server处于listen状态,等待别人随时来连接自己,listen就比如饭馆老板一天随时等待客人来吃饭。然后,我们可以添加一个_isrunning的成员变量,以表明服务器的运行状态,初始化为false。
在server处于listen状态后,因为tcp是需要连接的,需要使用accept函数来获取连接:
其中,第一个参数是server的套接字,后两个参数是用来得到是谁来连接server。关键在于accept的返回值:
我们看到accept的返回值竟然是一个文件描述符,这就让我们有点蒙圈了。因为在之前写udp代码时,只有一个文件描述符,那么此时我们难免有这样两个疑问:
- return fd是什么?
- return fd 和 _sockfd的关系
我们来将一个小故事,比如你和你的朋友去杭州西湖玩,在那里附近有很多饭馆,有一家叫西湖鱼庄,这家店雇了张三在店外面拉客,正好你在饭点碰到这家饭馆,就被拉了进去吃饭,张三带着你们进了饭店门口,然后张三喊来客人了,出来个人招呼客人,然后李四就出来招呼你们了。然后,张三又去店外面继续拉客,过了不久,张三又拉来了几个客人,到了店里喊又来客人了,出来个人招呼,此时王五出来招呼这几个客人,张三又跑出去继续拉客。在这个过程中,张三不给客人提供服务,只负责拉客。这个西湖鱼庄就是服务器,一个个客户就是一个个连接,而张三就是类成员_sockfd,李四、王五就相当于accept的返回值return fd,这个返回值来给连接提供服务,_sockfd就是用来协助accept获取新连接。把这个只负责获取连接的_sockfd叫做listensockfd(监听套接字)。
把成员变量改为_listensockfd。
如果张三拉客失败,也就是accept的返回值为0,那会怎么样呢?张三当然会继续拉客。
在提供服务时,由于udp是面向数据报,udp只能用recvfrom和sendto这样和网络强相关的接口,而tcp是面向字节流。之前我们学过C/C++的文件流以及管道的字节流,这些都是“流”,实际上它们都是一个东西,Linux下一切皆文件,所以网络、管道等都是文件,所以只要符合相同的流的特性,tcp这里的字节流的读取就相当于文件读取,也就是可以使用read/write进行读取。当使用read进行读取时,表明读取客户端结束(文件中表示读到文件结尾,这点有区别)。
在客户端这里,也是首先创建套接字,然后不需要显式bind,但是一定要有自己的IP和port,所以需要隐式bind,OS会用自己的IP和随机端口号去bind sockfd。客户端也不需要监听,没人回来连接客户端。server在等连接,所以客户端需要发起连接,使用connect调用,
那什么时候进行自动bind呢?在创建连接成功时就会bind!client的代码如下:
int main(int argc, char* argv[])
{if(argc != 3){std::cerr << "Usage: " << argv[0] << "server_ip server_port" << std::endl;exit(0);}std::string server_ip = argv[1];uint16_t server_port = std::stoi(argv[2]);//1.创建socketint sockfd = ::socket(AF_INET, SOCK_STREAM, 0);if(sockfd < 0){std::cerr << "create socket error" << std::endl;exit(1);}//2.connectstruct sockaddr_in server;memset(&server, 0 , sizeof(server));server.sin_family = AF_INET;server.sin_port = htons(server_port);::inet_pton(AF_INET, server_ip.c_str(), &server.sin_addr.s_addr);int n = ::connect(sockfd, (struct sockaddr*)&server, sizeof(server));if(n < 0){std::cerr << "connect socket error\n" << std::endl;exit(2);}while(true){std::string message;std::cout << "Enter# ";std::getline(std::cin, message);write(sockfd, message.c_str(), message.size());char echo_buffer[1024];int n = ::read(sockfd, echo_buffer, sizeof(echo_buffer)-1);if(n > 0){echo_buffer[n] = 0;std::cout << echo_buffer << std::endl;}else{break;}}::close(sockfd);return 0;
}
我们编译运行这份代码,当启动第一个客户端时,发现可以正常echo:
然后我们再启动第二个客户端,发现服务器没有和第二个客户端建立连接,也没有echo,
只有把第一个客户端退出后,服务器才能和第二个客户端建立连接,服务器才能echo第二个客户端,
因此,我们发现这版客户端代码没有并发处理能力,一次只能处理一个客户端,这时因为主线程一直在Service内部在运行:
所以,为了解决以上服务器端不能并发处理的问题,
V2_Echo_Server多进程版本
因此,我们在处理Service时,通过创建子进程来处理:
父子进程都要有独立的文件描述符表,而子进程的文件描述符表是从父进程那里拷贝来的,注定了父子进程指向了同样的文件,所以子进程肯定能看见创建的创建的sockfd(代码是共享的,数据以写时拷贝的方式各自私有一份),也就是说,父进程打开了多少个文件,子进程可以看到并且能访问。父进程创建的listensockfd是3文件描述符,子进程创建的sockfd是4号文件描述符,子进程从父进程拷贝了文件描述符表,所以和父进程指向同一个文件。因为子进程不关心3,只关心4,这里的建议是让子进程关闭listensockfd,只保留sockfd。同时要求父进程关闭sockfd,只保留listensockfd,这里是要求,如果父进程不关sockfd,相当于4号文件描述符一直被占用,如果再有客户端来连接服务器,只能使用5号文件描述符来处理,导致父进程的文件描述符一直在被打开而从来没有被关闭,文件描述符的本质就是数组的下标,数组下标肯定是有限个,这就导致了文件描述符泄漏的问题。
所以,我们期望的是父进程把自己该做的做完,然后去回到accept,继续等待被连接。而子进程去执行if(id ==0)内部的代码,这样就能做到服务器采用多进程的方式并发处理连接,
可是,父进程在waitpid时采用的是0(阻塞式等待),所以我们刚才想的理想过程不会发生,子进程在处理任务期间,父进程会阻塞等待,这不是还是一次只能处理一个连接吗?!那怎么解决呢?我们在学习信号的时候,子进程在退出时,会向父进程发送SIGCHID信号,如果对SIGCHID进程ingore,那父进程就不需要等子进程退出了,只负责连接就行了,这种方式是可行的也是最推荐的。
此外,我们还可以这样做:
在子进程中再创建子进程,也就是孙子进程。if(fork() > 0)exit(0)让子进程直接退了,直接留下孙子进程。子进程返回了,父进程就能等待成功然后返回了。当孙子进程处理完后,就会变成孤儿进程,被系统领养,就不用再关心这个孙子进程了。但是这不是最好方案,最好方案就是上面那种。
V3_Echo_Server多线程版本
创建新线程,主线程会等待新线程,这还是串行运行,不能实现并发访问。为此,我们想到之前学过线程分离,不再让主线程等待新线程,而是让新线程分离,
那用于执行任务的文件描述符sockfd怎么交给新线程呢?我们知道,新线程和主线程是共享同一张文件描述符表的,这里绝对不能让主线程和新线程关闭自己不用的套接字fd,也不需要了。我们把Execute函数设置为了static属性,不能访问类内方法,不能访问类内的Service方法,为此,我们创建一个内部类ThreadData:
V3-1_多线程远程命令执行
由远程发过来命令行字符串,server对命令行字符串进行执行,把执行结果返回给远程。建立Command.hpp头文件,
我们进行网络的读取,不仅仅可以使用read/write接口,还可以使用recv/send这一对接口,这两个接口不能用来读取udp,只能读取tcp,是面向字节流的读取。
recv/send的flags默认设为0。Command类的设计如下,HandlerCommand函数用于处理客户端传来的字符串,通过Excute函数来把传入的字符串做解释,
那在Excute拿到待解释的命令行字符串后,怎么解释这个字符串呢?我们可以使用popen函数调用:
popen内部会建立一个管道文件,然后创建子进程,执行对应的command命令,内部来帮我们做命令行解析,解析后的内容放到管道文件中,返回FILE*,让我们以文件的方式读取管道。换句话说,未来只需要命令字符串传给popen就可以了,像读文件一样把结果读出来。第二个参数type是"r"/"w"/"a"。通过pclose把对应的管道文件关闭。
class Command
{
public:Command(){_safe_command.insert("ls");_safe_command.insert("touch");_safe_command.insert("pwd");_safe_command.insert("whoami");_safe_command.insert("which"); }~Command(){}bool CheckSafe(const std::string& cmdstr){for(auto e : _safe_command){if(strncmp(e.c_str(), cmdstr.c_str(), e.size()) == 0){return true;}}return false;}std::string Excute(const std::string& cmdstr){if(!CheckSafe(cmdstr)) return "unsafe";FILE* fp = popen(cmdstr.c_str(), "r");std::string result;if(fp){char line[1024];while(fgets(line, sizeof(line), fp)){result += line;}return result;}return "excute error";}void HandlerCommand(int sockfd, InetAddr addr){while (true){char commandbuff[1024];ssize_t n = ::recv(sockfd, commandbuff, sizeof(commandbuff) - 1, 0); // TODOif (n > 0){commandbuff[n] = 0;LOG(INFO, "get command from client %s, command : %s\n", addr.AddrStr(), commandbuff); std::string result = Excute(commandbuff);::send(sockfd, result.c_str(), result.size(),0);}else if (n == 0){LOG(INFO, "client %s quit\n", addr.AddrStr().c_str());break;}else{LOG(ERROR, "read error: %s quit\n", addr.AddrStr().c_str());}}}
private:std::set<std::string> _safe_command;
};
运行结果如下:
实际上,我们打开Xshell,实际上是打开了一个客户端,在Xshell上输入命令,其实是将命令发送到远端,去请求服务器上的一个长启动的服务,把命令行字符串交给它,由它执行并推送给客户端执行结果。所以,我们所谓的命令执行就是推送到远端。
V4_Echo_Server线程池版本
实际上,这种Service长服务不太适合用线程池,因为线程池中的线程是有上限的,每个线程一直被占用。这次的线程池版本只是一个示例,未来还是要使用V2版本的多线程。创建任务类型task_t,这是线程池中任务的类型,
using func_t = std::function<void()>;
然后构建任务,放到线程池中去处理:
总结一下tcp,就是通过listensocket套接字去获取连接,把新连接和客户端地址交给别人去处理,可以多并发地去处理。
相关文章:
【Linux】TCP网络编程
目录 V1_Echo_Server V2_Echo_Server多进程版本 V3_Echo_Server多线程版本 V3-1_多线程远程命令执行 V4_Echo_Server线程池版本 V1_Echo_Server TcpServer的上层调用如下,和UdpServer几乎一样: 而在InitServer中,大部分也和UDP那里一样&…...
openGauss你计算的表大小,有包含toast表么?
openGauss你计算的表大小,有包含toast表么? 最近有一个同事问我说“openGauss中pg_relation_size函数在计算表的大小时是否包含了大字段的大小?”,经过思考后,自己觉得表的大小是不包含大字段的大小的,然后…...
Python字典的用法(定义、增加、删除、修改、查询、遍历)
一.字典的介绍 dictionary(字典)是除了列表以外的 Python 中最灵活的数据类型。dict(字典)可以采用多个数据,通常用于存储描述一个物体的相关信息。 字典和列表最主要的区别是,字典是无序的对象集合&#x…...
分布式锁的实现原理
作者:来自 vivo 互联网服务器团队- Xu Yaoming 介绍分布式锁的实现原理。 一、分布式锁概述 分布式锁,顾名思义,就是在分布式环境下使用的锁。众所周知,在并发编程中,我们经常需要借助并发控制工具,如 mute…...
linux(centos) 环境部署,安装JDK,docker(mysql, redis,nginx,minio,nacos)
目录 1.安装JDK (非docker)1.1 将文件放在目录下: /usr/local/jdk1.2 解压至当前目录1.3 配置环境变量 2.安装docker2.1 验证centos内核2.2 安装软件工具包2.3 设置yum源2.4 查看仓库中所有docker版本,按需选择安装2.5 安装docker2.6 启动docker 并 开机…...
批量生成不同用户的pdf 文件(html样式)
技术 selenium thymeleaf itextpdf chromedriver 使用thymeleaf 将动态数据替换 使用selenium chromedriver 进行js ,css等逻辑运算后渲染视图 使用itextpdf 将html 转为pdf 文件 html模板 <!DOCTYPE html> <html xmlns:th"http://www.thymeleaf…...
常见的排序算法
一、基于比较的排序算法 基于比较的排序算法通过比较元素之间的大小来完成排序。 1.1 冒泡排序(Bubble Sort) 特点:通过多次交换相邻元素,将最大(或最小)元素“冒泡”到序列末端。时间复杂度:…...
从语法、功能、社区和使用场景来比较 Sass 和 LESS
一:可以从语法、功能、社区和使用场景来比较 Sass 和 LESS: 1:语法 原始的 Sass 采用的是缩进而不是大括号,后续的 Sass 版本与 LESS 一样使用与 CSS 类似的语法: address {.fa.fa-mobile-phone {margin: 0 3px 0 2…...
hdlbits系列verilog解答(Exams/m2014 q4b)-87
文章目录 一、问题描述二、verilog源码三、仿真结果一、问题描述 本节学习如何实现下图中的电路。 模块声明 module top_module ( input clk, input d, input ar, // asynchronous reset output q); 思路: 只是实现一种带异步复位的D触发器。 时钟边沿两种触发方式的关键字…...
Python 和 Pyecharts 对Taptap相关数据可视化分析
结果展示: 数据来源: Python爬取TapTap 热门游戏信息并存储到数据库(详细版) 目录 结果展示: 数据来源: Python爬取TapTap 热门游戏信息并存储到数据库(详细版 一、引言 二、准备工作 三、…...
系统学习算法: 专题二 滑动窗口
题目一: 算法原理: 依然第一反应是暴力枚举,将所有的子数组都枚举出来,找到满足条件的长度最小的子数组,但是需要两层循环,时间复杂度来到O(N^2) 接下来就该思考如何进行优化 如果…...
Docker的save和export命令的区别,load和import的区别 笔记241124
Docker的save和export命令的区别,load和import的区别 解说1: Docker的save和export命令,以及load和import命令,在功能和使用场景上存在显著的区别。以下是对这两组命令的详细对比和解释: Docker save和export命令的区别 使用方式和目的&am…...
cad中为什么不使用C0C1C2连续,而使用G0G1G2连续
在CAD中,之所以使用G0、G1、G2连续而不是C0、C1、C2连续,主要是因为G连续性更侧重于几何空间的连续性,与视觉感知和制造过程更为相关。 • G0连续:保证曲线或曲面在连接点处没有断开,即位置连续。这在CAD中非常重要&a…...
Linux:makefile的使用
makefile小结: makefile的应用: 一个简单的 Makefile 文件包含一系列的“规则”,其样式如下: 目标(target)…: 依赖(prerequiries)… 命令(command) 目标(target)通常是要生成的文件的名称,可以是可执行文件或OBJ文件…...
局域网的网络安全
网络安全 局域网基本上都采用以广播为技术基础的以太网,任何两个节点之间的通信数据包,不仅为这两个节点的网卡所接收,也同时为处在同一以太网上的任何一个节点的网卡所截取。因此,黑客只要接入以太网上的任一节点进行侦听&#…...
【Leetcode 每日一题 - 补卡】3235. 判断矩形的两个角落是否可达
问题背景 给你两个正整数 x C o r n e r xCorner xCorner 和 y C o r n e r yCorner yCorner 和一个二维整数数组 c i r c l e s circles circles,其中 c i r c l e s [ i ] [ x i , y i , r i ] circles[i] [x_i, y_i, r_i] circles[i][xi,yi,ri] 表示…...
Android Studio安装TalkX AI编程助手
文章目录 TalkX简介编程场景 TalkX安装TalkX编程使用ai编程助手相关文章 TalkX简介 TalkX是一款将OpenAI的GPT 3.5/4模型集成到IDE的AI编程插件。它免费提供特定场景的AI编程指导,帮助开发人员提高工作效率约38%,甚至在解决编程问题的效率上提升超过2倍…...
C++类型转换
C类型转换 1.C语言中的类型转换2.C强制类型转换2.1.static_cast2.2.reinterpret_cast2.3.const_cast2.4.dynamic_cast 3.RTTI 🌟🌟hello,各位读者大大们你们好呀🌟🌟 🚀🚀系列专栏:【…...
241127学习日志——[CSDIY] [InternStudio] 大模型训练营 [20]
CSDIY:这是一个非科班学生的努力之路,从今天开始这个系列会长期更新,(最好做到日更),我会慢慢把自己目前对CS的努力逐一上传,帮助那些和我一样有着梦想的玩家取得胜利!!&…...
关于函数式接口和编程的解析和案例实战
文章目录 匿名内部类“匿名”在哪里 函数式编程lambda表达式的条件Supplier使用示例 ConsumeracceptandThen使用场景 FunctionalBiFunctionalTriFunctional 匿名内部类 匿名内部类的学习和使用是实现lambda表达式和函数式编程的基础。是想一下,我们在使用接口中的方…...
基于米尔全志T527开发板的FacenetPytorch人脸识别方案
本篇测评由优秀测评者“小火苗”提供。 本文将介绍基于米尔电子MYD-LT527开发板(米尔基于全志 T527开发板)的FacenetPytorch人脸识别方案测试。 一、facenet_pytorch算法实现人脸识别 深度神经网络 1.简介 Facenet-PyTorch 是一个基于 PyTorch 框架实…...
Java基础面试题11:简述System.gc()和Runtime.gc()的作用?
System.gc() 和 Runtime.gc() 是 Java 中用于提示 JVM(Java 虚拟机)进行垃圾回收的两个方法。它们的作用类似,但也有一些细微的区别。下面我们来详细说明。 System.gc() 和 Runtime.gc() 的区别 简单来说,System.gc() 等同于 Run…...
物料理解笔记·蓝白段子线·端子线座子焊接反了怎么处理!!!
目录 蓝白端子排线 端子线座子焊接错了怎么办 端子线如何拆线 编写不易,请勿搬运,仅供学习,感谢理解 蓝白端子排线 蓝白端子排线,这种端子线常用与编码电机的接线,或者在板子上通过提供段子线的接口,通…...
string接口模拟实现2
文章目录 浅拷贝insert插入一个字符insert插入一个字符串删除erasefind(查找一个字符)\\\\\\\find(查找一个字符串:子串substr)查找的练习(网址)赋值operator比较大小 浅拷贝 //浅拷贝string::string(const string& str){//开一样大的空间࿰…...
第 42 章 - Go语言 设计模式
在Go语言中,设计模式是一种被广泛接受的解决常见问题的最佳实践。这些模式可以分为三类:创建型模式、结构型模式和行为型模式。下面我将结合案例以及源代码对这三种类型的设计模式进行详细讲解。 创建型模式 创建型模式主要关注对象的创建过程…...
使用redis-plus-plus库连接redis
使用redis-plus-plus库连接redis 一、安装redis-plus-plus1.1安装hiredis1.2编译安装redis-plus-plus 二、redis的连接使用2.1创建redis对象2.2向redis中添加元素2.3判断元素是否存在2.4获取元素2.5设置获取过期时间2.6获取类型2.7 删除当前数据库 一、安装redis-plus-plus C …...
qt QGraphicsRotation详解
1、概述 QGraphicsRotation 是 Qt 框架中 QGraphicsTransform 的一个子类,它专门用于处理图形项的旋转变换。通过 QGraphicsRotation,你可以对 QGraphicsItem(如形状、图片等)进行旋转操作,从而创建动态和吸引人的视觉…...
嵌入式Qt使用ffmpeg视频开发记录
在此记录一下Qt下视频应用开发的自学历程,可供初学者参考和避雷。 了解常用音频格式yuv420p、h264等了解QML,了解QVideoOutput类的使用,实现播放yuv420p流参考ffmpeg官方例程,调用解码器实现h264解码播放 不需要手动分帧。ffmpeg…...
《String类》
目录 一、定义与概述 二、创建字符串对象 2.1 直接赋值 2.2 使用构造函数 三、字符串的不可变性 四、常用方法 4.1 String对象的比较 4.1.1 比较是否引用同一个对象 4.1.2 boolean equals(Object anObject)方法:按照字典序比较 4.1.3 int compareTo(Strin…...
Java—Properties类
Properties类是Java中用于处理属性文件(.properties文件)的类。属性文件是一种简单的文本文件,用于存储键值对数据,常用于保存配置信息。 Properties类继承自Hashtable类,它的键和值都是字符串类型。它提供了一些方法…...
wireshark抓包TR069协议
Wireshark是一个网络协议分析器,它允许用户捕获和详细查看网络流量。TR069协议是CPE(Customer Premises Equipment,用户驻地设备)和ACS(Auto-Configuration Server,自动配置服务器)之间沟通的通…...
【连接池】.NET开源 ORM 框架 SqlSugar 系列
.NET开源 ORM 框架 SqlSugar 系列 【开篇】.NET开源 ORM 框架 SqlSugar 系列【入门必看】.NET开源 ORM 框架 SqlSugar 系列【实体配置】.NET开源 ORM 框架 SqlSugar 系列【Db First】.NET开源 ORM 框架 SqlSugar 系列【Code First】.NET开源 ORM 框架 SqlSugar 系列【数据事务…...
FileReader和 FileWriter
FileReader和FileWriter是用于操作文件的类,它们分别用于读取和写入数据。下面是它们的一些基本用法: FileReader: 创建一个FileReader对象,指定要读取的文件路径。使用read()方法读取文件的内容,返回一个整数字符表…...
html 中的 <code>标签
定义和用途 <code> 标签是HTML中的一个内联元素,用于定义计算机代码片段。当你需要在网页内容中展示代码,比如编程语言代码(如JavaScript、Python、Java等)、命令行指令、标记语言代码(如HTML、XML等)…...
使用Apache HttpClient发起一个POST HTTP请求
Apache HttpClient 是一个强大的Java库,用于处理HTTP请求。 它支持多种HTTP方法,包括GET、POST、PUT、DELETE等。 本教程将重点介绍如何使用Apache HttpClient发送POST HTTP请求。 POST请求通常用于向服务器发送数据以创建或更新资源。 我们将演示如…...
Android复习代码1-4章
public class RudioButton extends AppCompatActivity {Overrideprotected void onCreate(Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_rudio_button);// 找到RadioGroup和TextView的实例RadioGroup radioGrou…...
CSS新特性(11)
一.计算盒子宽度calc函数,可以用加减乘除来计算 -*/ 让父盒子永远比子盒子小30像素 二.CSS3过渡transition搭配hover一起使用 该盒子宽度可以从200px到400px,谁做变化给谁加 不仅要写宽还要写高利用逗号,多个属性一起写都用逗号 既想要宽度变又想要高度…...
架构-微服务-服务网关
文章目录 前言一、网关介绍1. 什么是API网关2. 核心功能特性3. 解决方案 二、Gateway简介三、Gateway快速入门1. 基础版2. 增强版3. 简写版 四、Gateway核心架构1. 基本概念2. 执行流程 五、Gateway断言1. 内置路由断言工厂2. 自定义路由断言工厂 六、过滤器1. 基本概念2. 局部…...
Leetcode(区间合并习题思路总结,持续更新。。。)
讲解题目:合并区间 以数组 intervals 表示若干个区间的集合,其中单个区间为 intervals[i] [starti, endi] 。请你合并所有重叠的区间, 并返回一个不重叠的区间数组,该数组需恰好覆盖输入中的所有区间。示例 1:输入&a…...
11.21c++中的函数
练习: 编写mystring类:拥有以下功能: 1.带参、无参构造函数,拷贝构造函数,析构函数 2.编写 append(const mystring r) 为当前字符串尾部,拼接新的字符串r 3.编写 isEqual(const mystring r) 判断当前字符串…...
Rook入门:打造云原生Ceph存储的全面学习路径(下)
文章目录 六.Rook部署云原生CephFS文件系统6.1 部署cephfs storageclass6.2 创建容器所需cephfs文件系统6.3创建容器pod使用rook-cephfs提供pvc6.4 查看pod是否使用rook-cephfs 七.Ceph Dashboard界面7.1 启用dashboard开关7.2 ceph-dashboard配置外部访问7.3 Dashboard web ad…...
UI控件使用说明
文章目录 一、控件的公共属性二、常用控件的私有属性三、控件的显示与隐藏 一、控件的公共属性 struct element {u32 highlight: 1; //高亮标志u32 state: 3; //内核记录控件的状态u32 ref: 5; //内核计数值u32 prj: 3; //工程序号u32 hide_action: 1; //HIDE_WI…...
Java面向对象.抽象
目录 1.object类 一、Object类的地位 所有类的父类 2.抽象类 一、定义与声明 抽象类的概念 二、抽象方法 抽象方法的特点 三、继承抽象类 子类的责任 3.抽象方法基础理念 1.抽象方法的特征 2.将abstaract加在方法的前面,该类无法被继承 1.首先࿰…...
uniapp在小程序连接webScoket实现余额支付
webScoket文档:uni.connectSocket(OBJECT) | uni-app官网 /plugins/event.js const Dep function() {this.Evens Object.create(null); } class Event {constructor({dep new Dep()} {}) {if (dep.constructor Object && Object.keys(dep).length 0…...
【C语言】连接陷阱探秘(4):检查外部类型
目录 一、外部类型概述 1.1. 外部类型的重要性 1.2. 外部类型在C语言中的使用 1.3. 注意事项 二、常见的外部类型陷阱 2.1. 结构体和联合体的大小不匹配 2.1.1. 示例代码 2.1.2. 正确的做法 2.2. 枚举类型的值不匹配 2.3. 函数签名不一致 2.3.1. 函数签名不一致的问…...
Hexo博客在多个设备同步
title: ‘Hexo博客在多个设备同步’ date: 2024-11-28 19:08:08 categories: Hexo教程 cover: /img/cover4.jpg description: ‘实现Hexo博客在不同的设备上都可以使用和上传’ 博客链接1 :Hexo搭建博客的多终端同步问题 博客链接2:Hexo博客多台电脑设备同步管理 …...
Pytorch使用手册-使用 TensorBoard 可视化模型、数据和训练过程(专题十)
在 60 分钟速成课程中,我们展示了如何加载数据,将其传递通过我们定义的作为 nn.Module 子类的模型,训练该模型并在测试数据上进行测试。为了查看发生了什么,我们在模型训练过程中打印一些统计信息,以便了解训练是否进展顺利。然而,我们可以做得更好:PyTorch 与 TensorBo…...
Linux网络——NAT/代理服务器
一.NAT技术 1.NAT IP转换 之前我们讨论了, IPv4 协议中, IP 地址数量不充足的问题,NAT 技术就是当前解决 IP 地址不够用的主要手段, 是路由器的一个重要功能。 NAT 能够将私有 IP 对外通信时转为全局 IP. 也就是一种将私有 IP 和全局IP 相互转化的技术方法: 很…...
使用ffmpeg命令实现视频文件间隔提取帧图片
将视频按每隔五秒从视频中提取一张图片 使用 ffmpeg 工具,通过设置 -vf(视频过滤器)和 -vsync 选项 命令格式 ffmpeg -i input_video.mp4 -vf "fps1/5" output_%03d.png 解释: -i input_video.mp4:指定输…...
Elasticsearch实战:从搜索到数据分析的全面应用指南
Elasticsearch(简称 ES)是一个强大的分布式搜索引擎和分析工具,它能够快速处理海量数据,并提供全文检索、结构化搜索、数据分析等功能。在现代系统中,它不仅是搜索的核心组件,也是数据分析的有力工具。 本文…...