【网络通信】socket编程——TCP套接字
TCP依旧使用代码来熟悉对应的套接字,很多接口都是在udp中使用过的
所以就不会单独把他们拿出来作为标题了,只会把第一次出现的接口作为标题
文章目录
- 服务端 tcp_server
- tcpserver.hpp(封装)
- 初始化 initServer
- 1. 创建socket
- 2. 绑定 bind
- htons —— 主机序列转化为网络序列
- 3.监听
- listen ——设为 监听状态
- 启动 Start
- 1.获取连接,accept
- accept
- accept返回的文件描述符 与 socket设置成功返回的文件描述符的关系
- 2.获取新连接成功,开始进行业务处理
- tcpserver.cc (主函数main实现)
- 客户端 tcp_client
- tcpclient.cc(不封装,直接实现)
- 1.创建套接字
- 2.发起链接
- inet_addr——字符串IP地址 转为 网络序列IP地址
- 3. 链接成功
- 具体代码实现
- err.hpp(用于存放错误信息)
- makefile
- tcpServer.hpp( 服务端 封装)
- tcpServer.cc( 服务端 主函数实现)
- tcpClient.cc(客户端 不封装)

通过TCP的套接字 ,来把数据交付给对方的应用层,完成双方进程的通信
服务端 tcp_server
tcpserver.hpp(封装)
在 tcpServer.hpp 中,创建一个命名空间 yzq 用于封装
在命名空间中,定义一个类 TcpServer
该类中包含 构造 析构 初始化(initServer) 启动(start)
初始化 initServer
1. 创建socket

设置监听端口号(后面会解释) ,需要端口号标识进程的唯一性

在类外设置一个默认端口号8888作为构造函数参数port的缺省值

创建套接字
输入 man socket

第一个参数 domain ,用于区分 进行网络通信还是 本地通信
若想为网络通信,则使用 AF_INET
若想为本地通信,则使用 AF_UNIX
第二个参数 type, 套接字对应的服务类型

SOCK_STREAM 流式套接
SOCK_DGRAM 无连接不可靠的通信(用户数据报)
第三个参数 protocol ,表示想用那种协议,协议默认为0
若为 流式套接,则系统会认为是TCP协议 ,若为用户数据报,则系统会认为是UDP协议
套接字的返回值:若成功则返回文件描述符,若失败则返回 -1

说明进行网络通信,流式套接,同时系统认为是TCP协议

创建err.hpp 用于存储错误信息的枚举

如果创建失败,则终止程序
2. 绑定 bind
输入 man 2 bind ,查看绑定

给一个套接字绑定一个名字
第一个参数 sockfd 为 套接字
第二个参数 addr 为 通用结构体类型
第三个参数 addrlen 为 第二个参数的实际长度大小
bind返回值:若成功,则返回0,若失败,返回 -1

使用bind,是需要借助一个通用结构体来实现的
所以定义一个 网络通信类型的结构体 local
在上一篇博客中,详细讲述了 sockaddr_in 结构体的内部组成
不懂可以去看看:struct sockaddr_in 的理解
htons —— 主机序列转化为网络序列
输入 man htons ,表示短整数的主机转网络序列

所以需要将主机的port_进行转化 ,然后再交给 local的sin_port (端口号)

INADDR_ANY 表示bind的任意IP

如果绑定失败返回-1
3.监听
listen ——设为 监听状态
输入 man 2 listen
设置当前套接字状态为 监听状态

第一个参数 sockfd 为 套接字
第二个参数 暂不做解释,一般设为整数
若成功则返回0,若失败返回-1

监听失败 返回-1,并终止程序

在类外设置一个 默认整数 为32
启动 Start

设置一个布尔变量 quit_,若为true则表示 服务器启动, 若为false,则表示 服务器没有启动
如果服务器没有启动,则进入while循环

1.获取连接,accept
accept
输入 man 2 accept

需要知道谁连的你,所以要获取到客户端的相关信息
第一个参数 sockfd 为套接字
第二个参数 addr 为通用结构体类型的 结构体 这个结构体是用来记录客户端内的port号以及IP地址 、16位地址类型等信息
第三个参数 addrlen 为 结构体的大小
返回值:
若成功,则返回一个合法的整数 即文件描述符
若失败,返回-1并且设置错误码
accept返回的文件描述符 与 socket设置成功返回的文件描述符的关系
如:有一个鱼庄,生意不太好,所以在外面站着一个人叫张三,进行揽客
有一天你和你的朋友在外面遇见张三,张三就向你们说他们鱼庄有多少,推荐去他们哪里吃鱼
正好你们俩也饿了,所以就跟张三去鱼庄吃鱼,但是只有你们进入鱼庄了,张三并没有进去
张三只是向里面喊了一声,来客人了,然后继续找人去了
这个时候来了一个服务员李四,向你们询问要吃什么,并向你们提供各种服务
每一次张三把客人招呼到鱼庄时,都会有一名服务员给客人提供服务
当张三做完自己的工作后,立马返回自己的工作岗位,继续招揽客人
张三不给用户提供具体的服务,只负责把客人从路上拉到店里去吃饭 进行消费
李四来给客人提供服务
鱼庄 可以看作是 整个服务器
像张三这样把客人从外部 拉到餐厅里的 称为 监听套接字 即accept的第一个参数 sockfd
像李四这样作的动作,相当于accept会返回一个文件描述符,这个文件描述符 是真正给用户提供IO服务的
若张三继续拉客,在路上碰见一个人,问他要不要去鱼庄吃饭,但那个人摇了摇头,表示没有意愿去鱼庄吃饭,
此时张三就被拒绝了,但这并不影响张三继续拉客去鱼庄
所以 accept 获取失败,只需继续 执行即可

2.获取新连接成功,开始进行业务处理
提供一个service的函数 ,参数为新的文件描述符sock
用于实现基本的读写服务 即 客户端发消息,需要把消息转回去
TCP 是一种流式服务
输入 man 2 read

从文件描述符fd中将我们想要的数据,按照数据块的方式读取出来
返回值代表多少字节,读取到文件结尾为0,失败为-1

将sock中的数据读取到buffer缓冲区中
若读取成功,则将最后一位的下一位赋值为0

若read的返回值为0,则对方将连接关闭了,所以sock也可以关闭

若返回值小于0,则读取失败,返回错误码
收到消息,需要把消息做某种处理后,再把消息转回去
所以使用 包装器 functional处理

在类外设置一个函数类型,返回值为string,参数为 string 的包装器

用该函数类型定义为一个私有变量func

将处理完的消息进行返回
输入 man 2 write
向一个文件中写入信息

fd代表文件描述符
buf代表 缓冲区
count代表 缓冲区大小
write将缓冲区的count大小的数据写入 fd中

将res中的数据 写入 sock文件描述符中
tcpserver.cc (主函数main实现)
想要只输入 ./tcp_server 加 端口号
所以在main函数中添加命令行参数
main函数的两个参数,char* argv[] 为指针数组 ,argv为一张表,包含一个个指针,指针指向字符串
int argc,argc为数组的元素个数

当参数输入不为2时,就会终止程序,同时打印出对应的输入参数

通过构造函数了解, 想要使用 new TcpServer 需要传入回调和端口号

客户端 tcp_client
tcpclient.cc(不封装,直接实现)
为了使用客户端,所以要输入对应的 可执行程序 serverip serverport
所以在main函数需要使用 命令行参数

若输入的参数少于3个,则终止程序,并打印出对应输入的参数

将输入的第二个参数的IP地址 赋值给 serverip
将输入的第三个参数的端口号,使用atoi将字符串转化为整数 ,再赋值给serverport
1.创建套接字

网络通信,并为流式套接,默认为0,因为流式所以为TCP协议
若创建套接字失败,则终止程序
2.发起链接
输入 man accept

客户端 通过套接字sockfd,向特定的服务器发起链接请求
sockfd:套接字
addr:公共类型的结构体 内部包含 服务器的IP地址和的端口号
addrlen:结构体的大小
返回值:若成功,则返回0,若失败,返回-1和错误码
首次发起链接时,操作系统会给客户端自动进行绑定端口
所以需要先定义一个结构体server

借助htons 将上述的主机序列端口号serverport 转化为网络序列端口号
inet_addr——字符串IP地址 转为 网络序列IP地址
输入man inet_addr

第一个参数为 字符串风格的IP地址
第二个参数 为 网络序列的IP地址
将 字符串风格的IP地址 转为 网络序列的IP地址

再将主机序列的IP地址serverip,转化为网络序列的IP地址

cnt表示重连次数
设置while循环,当不等于0链接失败时,cnt值减1,并重新链接,若cnt值为0,则break终止循环
若出了while循环,cont小于等于0,则终止程序
3. 链接成功

创建一个string类型的line,将输入的参数传入line中
使用write,将line的内容传入文件描述符中
使用read,将sock的数据传入buffer中
通过read的返回值来判断,若返回值大于0则,输出其中内容
若返回值等于0,则说明链接关闭,则退出while循环
若返回值小于,则说明创建失败,返回错误码
具体代码实现
err.hpp(用于存放错误信息)
#pragma once enum
{USAGE_ERR=1,SOCKET_ERR,//2BIND_ERR,//3LISTEN_ERR//4
};
makefile
.PHONY:all
all: tcp_client tcp_servertcp_client:tcpClient.ccg++ -o $@ $^ -std=c++11 -lpthread
tcp_server:tcpServer.ccg++ -o $@ $^ -std=c++11 -lpthread
.PHONY:clean
clean:rm -f tcp_client tcp_server
tcpServer.hpp( 服务端 封装)
#pragma once#include<iostream>
#include<cstdlib>
#include<string.h>
#include<unistd.h>
#include"err.hpp"
#include <sys/types.h>
#include <sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<functional>namespace yzq
{static uint16_t defaultport=8888;//默认端口号static const int backlog=32;//默认整数为32using func_t=std::function<std::string(const std::string&)>;class TcpServer;class ThreadData//该类用于存放客户端的IP port 套接字{ public:ThreadData(int fd,const std::string&ip,const uint16_t &port,TcpServer*ts)//构造:sock(fd),clientip(ip),clientport(port),current(ts){}public:int sock;//套接字std::string clientip;//客户端IPuint16_t clientport;//客户端端口号TcpServer*current;};class TcpServer{public:TcpServer(func_t func,uint16_t port=defaultport):func_(func),port_(port),quit_(true)//表示默认启动{}void initServer()//初始化{//1.创建socketlistensock_=socket(AF_INET,SOCK_STREAM,0);if(listensock_<0)//创建失败{std::cout<<" create socket errno"<<std::endl;exit(SOCKET_ERR);//终止程序}//2. bind 绑定struct sockaddr_in local;//网络通信类型//清空memset(&local,'\0',sizeof(local));local.sin_family=AF_INET;//网络通信//htons 主机转网络local.sin_port=htons(port_);//端口号local.sin_addr.s_addr=INADDR_ANY ; //IP地址if(bind(listensock_,(struct sockaddr*)&local,sizeof(local))<0)//失败返回-1{std::cout<<" bind socket errno"<<std::endl;exit(BIND_ERR);//终止程序}// 3.监听if(listen(listensock_,backlog)<0){//监听失败返回-1std::cout<<" listen socket errno"<<std::endl;exit(LISTEN_ERR);//终止程序}}void start()//启动{ quit_=false;//服务器没有启动while(!quit_){//4.获取连接,acceptstruct sockaddr_in client;//网络通信类型socklen_t len=sizeof(client);//结构体大小int sock=accept(listensock_,(struct sockaddr*)&client,&len); if(sock<0){//获取失败std::cout<<" accept errno"<<std::endl;continue;//继续执行}//提取客户端信息std::string clientip=inet_ntoa(client.sin_addr);//客户端ipuint16_t clientport=ntohs(client.sin_port);//客户端端口号//5.获取新连接成功,开始进行业务处理std::cout<<"获取新连接成功: "<<sock<<"from "<<listensock_<<std::endl; //service(sock);//多线程版本没有调用函数//多线程版本pthread_t tid;ThreadData*td=new ThreadData(sock,clientip,clientport,this);pthread_create(&tid,nullptr,threadRoutine,td);}}static void *threadRoutine(void*args){ pthread_detach(pthread_self());//线程分离ThreadData*td=(ThreadData*)args;td->current->service(td->sock);delete td;return nullptr;}void service(int sock){char buffer[1024];while(true){//将sock中的数据读取到buffer中ssize_t s=read(sock,buffer,sizeof(buffer)-1);if(s>0){//读取成功buffer[s]=0;//使用func 进行回调std::string res=func_(buffer);std::cout<<res<<std::endl;//将res中的数据写给sock中write(sock,res.c_str(),res.size());}else if(s==0){//说明对方将连接关闭了close(sock);std::cout<<"client quit,me too"<<std::endl;break; }else {//读取失败返回-1std::cout<<"read errno"<<strerror(errno)<<std::endl;break;}} }~TcpServer(){}private:func_t func_;//函数类型int listensock_;//监听套接字 bool quit_;//表示服务器是否启动uint16_t port_;//端口号};
}
tcpServer.cc( 服务端 主函数实现)
#include"tcpServer.hpp"
#include<memory>//智能指针
using namespace std;
using namespace yzq;static void usage(string proc)
{std::cout<<"usage:\n\t"<<proc<<"port\n"<<std::endl;
}std::string echo(const std::string&message)
{return message;
}
// ./tcp_server port
int main(int argc,char*argv[])
{//输入两个参数 所以不等于2if(argc!=2){usage(argv[0]);exit(USAGE_ERR);//终止程序}//将输入的端口号 转化为整数 uint16_t port=atoi(argv[1]);unique_ptr<TcpServer>tsvr(new TcpServer(echo,port));tsvr->initServer();//服务器初始化tsvr->start();//启动return 0;
}
tcpClient.cc(客户端 不封装)
#include<iostream>
#include<cstring>
#include<unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include"err.hpp"
using namespace std;static void usage(string proc)
{std::cout<<"usage:\n\t"<<proc<<"port\n"<<std::endl;
}//./tcp_client serverip serverport
int main(int argc,char*argv[])
{if(argc!=3){usage(argv[0]);exit(USAGE_ERR);//终止程序}std::string serverip=argv[1];//IP地址uint16_t serverport=atoi(argv[2]);//端口号//1.创建套接字int sock=socket(AF_INET,SOCK_STREAM,0);if(sock<0){//创建失败cout<<"socket errnr:"<<strerror(errno)<<endl;exit(SOCKET_ERR);//终止程序}//2.发起链接struct sockaddr_in server;memset(&server,0,sizeof(server));//清空server.sin_family=AF_INET;//网络通信类型//htons 主机序列转为网络序列server.sin_port=htons(serverport);//网络端口号inet_aton(serverip.c_str(),&server.sin_addr);//网络IP地址int cnt=5;//重连次数while(connect(sock,(struct sockaddr*)&server,sizeof(server))!=0){//不等于0则链接失败sleep(1);cout<<"正在尝试重连,重连次数还有:"<<cnt--<<endl;if(cnt<=0){//没有重连次数break;}}if(cnt<=0){//链接失败cout<<"链接失败.."<<endl;exit(SOCKET_ERR);//终止程序}char buffer[1024];//3.链接成功while(true){string line;cout<<"enter>>";getline(cin,line);//从cin中获取内容 写入line中write(sock,line.c_str(),line.size());//将line中的内容写入到sock文件描述符中 ssize_t s=read(sock,buffer,sizeof(buffer)-1);if(s>0){buffer[s]=0;cout<<"server echo"<<buffer<<endl;}else if(s==0){cout<<"server quit"<<endl;break;}else {cout<<"read errno"<<strerror(errno)<<endl;break;}}close(sock);return 0;
}
相关文章:

【网络通信】socket编程——TCP套接字
TCP依旧使用代码来熟悉对应的套接字,很多接口都是在udp中使用过的 所以就不会单独把他们拿出来作为标题了,只会把第一次出现的接口作为标题 文章目录 服务端 tcp_servertcpserver.hpp(封装)初始化 initServer1. 创建socket2. 绑定 bindhtons —— 主机序…...
ROS2系统学习番外篇2---用VSCode开发ROS2程序
在ROS2系统学习3—第一个“Hello World”程序—即工作空间创建与包创建中已经介绍了如何创建ROS的工作空间以及包。在开发大型工程时,往往需要在IDE下面进行开发,因此本篇介绍使用VSCode来搭建ROS2开发环境的方法。 首先用VSCode打开ROS2的工作空间。 使用快捷键编译ROS2 …...

06 - Stream如何提高遍历集合效率?
前面我们讲过 List 集合类,那我想你一定也知道集合的顶端接口 Collection。 在 Java8 中,Collection 新增了两个流方法,分别是 Stream() 和 parallelStream()。 1、什么是 Stream? 现在很多大数据量系统中都存在分表分库的情况…...

【Spring】使用注解的方式获取Bean对象(对象装配)
目录 一、了解对象装配 1、属性注入 1.1、属性注入的优缺点分析 2、setter注入 2.1、setter注入的优缺点分析 3、构造方法注入 3.1、构造方法注入的优缺点 二、Resource注解 三、综合练习 上一个博客中,我们了解了使用注解快速的将对象存储到Spring中&#x…...

[webpack] 基本配置 (一)
文章目录 1.基本介绍2.功能介绍3.简单使用3.1 文件目录和内容3.2 下载依赖3.3 启动webpack 4.基本配置4.1 五大核心概念4.2 基本使用 1.基本介绍 Webpack 是一个静态资源打包工具。它会以一个或多个文件作为打包的入口, 将我们整个项目所有文件编译组合成一个或多个文件输出出去…...

模板学堂|SQL数据集动态参数使用场景及功能详解
DataEase开源数据可视化分析平台于2022年6月正式发布模板市场(https://dataease.io/templates/)。模板市场旨在为DataEase用户提供专业、美观、拿来即用的仪表板模板,方便用户根据自身的业务需求和使用场景选择对应的仪表板模板&a…...

Wlan——射频和天线基础知识
目录 射频的介绍 射频和Wifi 射频的相关基础概念 射频的传输 信号功率的单位 射频信号传输行为 天线的介绍 天线的分类 天线的基本原理 天线的参数 射频的介绍 射频和Wifi 什么是射频 从射频发射器产生一个变化的电流(交流电),通过…...
前端实习周记第三周周记
第二周总结 第二周主要是做了一些PC端细节内容。大的地方改的不多,但是小的细节蛮多。 值得一提的是,第二周做的微信小程序,改了很多逻辑。改逻辑需要与后端进行联调,收获很大,思路也愈发清楚。 记录做了什么是好习…...
Android 13 Launcher界面——移除Launcher的删除和卸载功能
目录 一.背景 二.将卸载功能进行屏蔽 三.将移除功能屏蔽 四.将Remove按钮与Uninstall按钮屏蔽...

深度学习:使用卷积神经网络CNN实现MNIST手写数字识别
引言 本项目基于pytorch构建了一个深度学习神经网络,网络包含卷积层、池化层、全连接层,通过此网络实现对MINST数据集手写数字的识别,通过本项目代码,从原理上理解手写数字识别的全过程,包括反向传播,梯度…...

docker search 镜像报错: connect: no route to host (桥接模式配置静态IP)
如下 原因 可能有多种: ① 没有开放防火墙端口 ② ip地址配置有误 解决 我是因为虚拟机采用了桥接模式,配置静态ip地址有问题。 先确认虚拟机采用的是 桥接模式,然后启动虚拟机。 1、打开命令行,输入下面指令,打开…...
【VUE】[Violation] Added non-passive event listener to a scroll-blocking...
环境 chrome: 115.0.5790.170vue: ^3.3.4element-plus: ^2.3.4vite: ^4.4.7 问题 [Violation] Added non-passive event listener to a scroll-blocking <某些> 事件. Consider marking event handler as passive to make the page more responsive. See <URL> …...
runit-docker中管理多个服务
runit-docker中管理多个服务 介绍Runit, systemctl和supervisor是三种不同的服务管理工具区别runit优点程序构成快速开始runit实现服务退出执行指定操作runit监管服务打印日志到syslogrunit监管服务后台运行runit监管服务一些错误总结 介绍 runit 是一个轻量级的、稳定的、跨平…...

Intune 应用程序管理
由于云服务提供了增强的安全性、稳定性和灵活性,越来越多的组织正在采用基于云的解决方案来满足他们的需求。这正是提出Microsoft Endpoint Manager等解决方案的原因,它结合了SCCM和Microsoft Intune,以满足本地和基于云的端点管理。 与 Int…...

Oracle DB 安全性 : TDE HSM TCPS Wallet Imperva
• 配置口令文件以使用区分大小写的口令 • 对表空间进行加密 • 配置对网络服务的细粒度访问 TCPS 安全口令支持 Oracle Database 11g中的口令: • 区分大小写 • 包含更多的字符 • 使用更安全的散列算法 • 在散列算法中使用salt 用户名仍是Oracle 标识…...

leetcode27—移除元素
思路: 参考26题目双指针的思想,只不过这道题不是快慢指针。 看到示例里面数组是无序的,也就是说后面的元素也是可能跟给定 val值相等的,那么怎么处理呢。就想到了从前往后遍历,如果left对应的元素 val时,…...
flask---》更多查询方式/连表查询/原生sql(django-orm如何执行原生sql)/flask-sqlalchemy
更多查询方式 #1 查询: filer:写条件 filter_by:等于的值 # 查询所有 是list对象 res session.query(User).all() # 是个普通列表 print(type(res)) print(len(res))# 2 只查询某几个字段 # select name as xx,email from user; res session.…...
Chromium内核浏览器编译记(三)116版本内核UI定制
转载请注明出处:https://blog.csdn.net/kong_gu_you_lan/article/details/132180843?spm1001.2014.3001.5501 本文出自 容华谢后的博客 往期回顾: Chromium内核浏览器编译记(一)踩坑实录 Chromium内核浏览器编译记(…...

LoRaWan网关设计架构介绍
LoRa 数据包转发器是在基于 LoRa 的网关(带或不带 GPS)主机上运行的程序。它将集中器(上行链路)接收到的 RF 数据包通过安全的 IP 链路转发到LoRaWAN 网络服务器( LNS )。它还通过相同的安全 IP 将 LNS(下行链路)发送的 RF 数据包传输到一台或多台设备。此外,它还可以传…...
vue 全局状态管理(简单的store模式、使用Pinia)
目录 为什么使用状态管理简单的store模式服务器渲染(SSR) pinia简介示例1. 定义一个index.ts文件2. 在main.ts中引入3. 定义4. 使用 为什么使用状态管理 多个组件可能会依赖同一个状态时,我们有必要抽取出组件内的共同状态集中统一管理&…...
连锁超市冷库节能解决方案:如何实现超市降本增效
在连锁超市冷库运营中,高能耗、设备损耗快、人工管理低效等问题长期困扰企业。御控冷库节能解决方案通过智能控制化霜、按需化霜、实时监控、故障诊断、自动预警、远程控制开关六大核心技术,实现年省电费15%-60%,且不改动原有装备、安装快捷、…...
JVM垃圾回收机制全解析
Java虚拟机(JVM)中的垃圾收集器(Garbage Collector,简称GC)是用于自动管理内存的机制。它负责识别和清除不再被程序使用的对象,从而释放内存空间,避免内存泄漏和内存溢出等问题。垃圾收集器在Ja…...

Python实现prophet 理论及参数优化
文章目录 Prophet理论及模型参数介绍Python代码完整实现prophet 添加外部数据进行模型优化 之前初步学习prophet的时候,写过一篇简单实现,后期随着对该模型的深入研究,本次记录涉及到prophet 的公式以及参数调优,从公式可以更直观…...

华为OD机试-食堂供餐-二分法
import java.util.Arrays; import java.util.Scanner;public class DemoTest3 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseint a in.nextIn…...
Spring Boot+Neo4j知识图谱实战:3步搭建智能关系网络!
一、引言 在数据驱动的背景下,知识图谱凭借其高效的信息组织能力,正逐步成为各行业应用的关键技术。本文聚焦 Spring Boot与Neo4j图数据库的技术结合,探讨知识图谱开发的实现细节,帮助读者掌握该技术栈在实际项目中的落地方法。 …...
06 Deep learning神经网络编程基础 激活函数 --吴恩达
深度学习激活函数详解 一、核心作用 引入非线性:使神经网络可学习复杂模式控制输出范围:如Sigmoid将输出限制在(0,1)梯度传递:影响反向传播的稳定性二、常见类型及数学表达 Sigmoid σ ( x ) = 1 1 +...

Chromium 136 编译指南 Windows篇:depot_tools 配置与源码获取(二)
引言 工欲善其事,必先利其器。在完成了 Visual Studio 2022 和 Windows SDK 的安装后,我们即将接触到 Chromium 开发生态中最核心的工具——depot_tools。这个由 Google 精心打造的工具集,就像是连接开发者与 Chromium 庞大代码库的智能桥梁…...

【免费数据】2005-2019年我国272个地级市的旅游竞争力多指标数据(33个指标)
旅游业是一个城市的重要产业构成。旅游竞争力是一个城市竞争力的重要构成部分。一个城市的旅游竞争力反映了其在旅游市场竞争中的比较优势。 今日我们分享的是2005-2019年我国272个地级市的旅游竞争力多指标数据!该数据集源自2025年4月发表于《地理学报》的论文成果…...
游戏开发中常见的战斗数值英文缩写对照表
游戏开发中常见的战斗数值英文缩写对照表 基础属性(Basic Attributes) 缩写英文全称中文释义常见使用场景HPHit Points / Health Points生命值角色生存状态MPMana Points / Magic Points魔法值技能释放资源SPStamina Points体力值动作消耗资源APAction…...
【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/…...