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

高性能的 C++ Web 开发框架 CPPCMS + WebSocket 模拟实现聊天与文件传输案例。

1. 项目结构

在这里插入图片描述

2. config.json

{"service": {"api": "http","port": 8080,"ip": "0.0.0.0"},"http": {"script": "","static": "/static"}
}

3. CMakeLists.txt

cmake_minimum_required(VERSION 3.10)
project(c_web)set(CMAKE_CXX_STANDARD 17)# 指定源文件
set(SOURCE_FILES src/main.cpp src/blog.cpp)# 手动设置 CppCMS 和 Booster 的头文件路径
include_directories(/usr/local/include)# 手动设置库文件路径
link_directories(/usr/local/lib)# 添加可执行文件
add_executable(c_web ${SOURCE_FILES})find_package(Boost REQUIRED COMPONENTS system thread)
include_directories(${Boost_INCLUDE_DIRS})# 添加 nlohmann_json 的头文件路径
include_directories(/usr/include/nlohmann)# 链接 CppCMS 和 Booster 库
target_link_libraries(c_web cppcms booster ${Boost_LIBRARIES})

4. main.cpp

#include <cppcms/service.h>  // 引入CppCMS服务的头文件
#include <cppcms/applications_pool.h>  // 应用池管理类
#include <cppcms/http_response.h>  // 处理HTTP响应的类
#include <cppcms/url_dispatcher.h>  // URL调度器,用于将请求映射到处理程序
#include <boost/beast/core.hpp>  // Beast库的核心部分,用于处理输入输出操作
#include <boost/beast/websocket.hpp>  // Beast库的WebSocket部分,用于WebSocket处理
#include <boost/asio/ip/tcp.hpp>  // ASIO库的TCP/IP协议部分
#include <boost/asio/io_context.hpp>  // ASIO库的IO上下文,用于管理异步操作
#include <boost/asio/strand.hpp>  // ASIO库的strand,用于确保回调顺序
#include <thread>  // C++标准库的线程支持
#include <mutex>  // C++标准库的互斥锁,用于线程安全操作
#include <set>  // C++标准库的集合容器
#include <vector>  // C++标准库的向量容器
#include <iostream>  // 标准输入输出流
#include <fstream>  // 文件流,用于文件读写操作
#include <map>  // 映射容器,用于键值对存储
#include "blog.h"  // 自定义的博客应用程序头文件
#include <nlohmann/json.hpp>  // 引入nlohmann JSON库,用于处理JSON数据namespace beast = boost::beast;  // 简化命名空间
namespace websocket = beast::websocket;  // 简化命名空间
namespace net = boost::asio;  // 简化命名空间
using tcp = net::ip::tcp;  // 使用TCP协议
using json = nlohmann::json;  // 使用nlohmann JSON库进行JSON处理// 用于存储当前所有连接的用户及其对应的WebSocket连接
std::map<std::string, std::shared_ptr<websocket::stream<tcp::socket>>> user_connections;
// 用于确保线程安全地访问user_connections的互斥锁
std::mutex connections_mutex;// 处理每个WebSocket会话的函数
void do_session(std::shared_ptr<websocket::stream<tcp::socket>> ws) {std::string current_user;  // 存储当前用户的用户名try {ws->accept();  // 接受WebSocket连接while(1) {  // 无限循环处理接收的消息beast::flat_buffer buffer;  // 创建一个缓冲区来存储接收到的数据ws->read(buffer);  // 从WebSocket连接中读取数据std::string message = beast::buffers_to_string(buffer.data());  // 将缓冲区中的数据转换为字符串auto data = json::parse(message);  // 解析JSON格式的数据// 处理用户初始化(登录)请求if (data["type"] == "init") {current_user = data["username"];  // 获取并保存当前用户的用户名{// 使用互斥锁确保线程安全地更新user_connectionsstd::lock_guard<std::mutex> lock(connections_mutex);user_connections[current_user] = ws;  // 将用户与其WebSocket连接关联}// 构建一个包含所有已连接用户列表的JSON对象json user_list = { {"type", "user_list"}, {"users", json::array()} };for (const auto& pair : user_connections) {user_list["users"].push_back(pair.first);  // 将每个用户的用户名添加到列表中}// 将用户列表发送给所有已连接的用户for (const auto& pair : user_connections) {pair.second->text(true);  // 设置为文本消息pair.second->write(net::buffer(user_list.dump()));  // 发送用户列表}}// 处理普通消息传递请求else if (data["type"] == "message") {std::string target = data["target"];  // 获取消息的目标用户// 如果目标用户在线,则将消息转发给该用户if (user_connections.find(target) != user_connections.end()) {auto target_ws = user_connections[target];target_ws->text(true);  // 设置为文本消息target_ws->write(net::buffer(message));  // 将消息发送给目标用户}}// 处理文件元数据及文件传输请求else if (data["type"] == "metadata") {std::string target = data["target"];  // 获取文件传输的目标用户// 如果目标用户在线,则发送文件元数据,并准备接收文件内容if (user_connections.find(target) != user_connections.end()) {auto target_ws = user_connections[target];target_ws->text(true);  // 发送文件元数据target_ws->write(net::buffer(message));beast::flat_buffer file_buffer;  // 准备接收文件内容的缓冲区ws->read(file_buffer);  // 从发送者处读取文件内容target_ws->binary(true);  // 设置为二进制消息target_ws->write(file_buffer.data());  // 将文件内容转发给目标用户}}}} catch (std::exception const& e) {  // 捕获并处理异常std::cerr << "WebSocket Error: " << e.what() << std::endl;  // 打印错误信息}// 清理连接,确保在连接断开时从用户列表中移除用户std::lock_guard<std::mutex> lock(connections_mutex);if (!current_user.empty()) {user_connections.erase(current_user);  // 从连接映射中移除当前用户}
}// 程序入口
int main(int argc, char* argv[]) {try {cppcms::service app(argc, argv);  // 创建CppCMS服务对象// 启动WebSocket服务器线程std::thread websocket_thread([]() {net::io_context ioc{1};  // 创建IO上下文对象tcp::acceptor acceptor{ioc, tcp::endpoint(tcp::v4(), 8081)};  // 创建TCP接受器,监听8081端口for (;;) {  // 无限循环,处理每个新的连接auto socket = std::make_shared<websocket::stream<tcp::socket>>(ioc);acceptor.accept(socket->next_layer());  // 接受新的TCP连接,并将其提升为WebSocket连接std::thread(&do_session, socket).detach();  // 为每个连接启动一个新的会话线程}});// 启动CppCMS服务app.applications_pool().mount(cppcms::applications_factory<blog>());  // 将博客应用挂载到服务池中app.run();  // 运行服务websocket_thread.join();  // 等待WebSocket线程结束} catch (std::exception const &e) {  // 捕获并处理异常std::cerr << "Error: " << e.what() << std::endl;  // 打印错误信息return EXIT_FAILURE;  // 以失败状态退出程序}
}

说明:WebSocket服务端口:8081,CppCMS服务端口:8080

5. blog.h

#ifndef BLOG_H
#define BLOG_H
#include <cppcms/application.h>
#include <cppcms/http_response.h>
#include <cppcms/url_dispatcher.h>
#include <cppcms/url_mapper.h>
#include <fstream>
class blog : public cppcms::application {
public:blog(cppcms::service &srv);void index();
private:void serve_html(const std::string &path);};
#endif

6. blog.cpp

#include "blog.h"blog::blog(cppcms::service &srv) : cppcms::application(srv) {dispatcher().map("GET", "/", &blog::index, this);
}void blog::index() {serve_html("./views/index.html");
}void blog::serve_html(const std::string &path) {std::ifstream file(path);if (file.is_open()) {std::string content((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());response().out() << content;} else {response().status(404);response().out() << "Page not found";}
}

7. index.html

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>File Transfer and Chat</title><!-- 引入 Vue.js 和 Element-UI (包含图标支持) --><script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.min.js"></script><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/element-ui@2.15.9/lib/theme-chalk/index.css"><script src="https://cdn.jsdelivr.net/npm/element-ui@2.15.9/lib/index.js"></script>
</head>
<body><div id="app"><el-container><el-header><h2>实时聊天与文件传输</h2></el-header><el-main><el-row :gutter="20"><el-col :span="6"><el-select v-model="selectedUser" placeholder="选择一个用户" style="width: 100%;"><el-optionv-for="user in users":key="user":label="user":value="user"></el-option></el-select></el-col></el-row><el-row><el-col :span="24"><div id="chatbox" class="chatbox"><el-card v-for="(msg, index) in messages" :key="index" class="box-card"><p><strong>{{ msg.sender }}:</strong><!-- 图片预览 --><template v-if="msg.isImage">{{ msg.content }} <br><img :src="msg.url" alt="Image Preview" style="max-width: 100px; max-height: 100px;"></template><!-- 文件下载链接 --><template v-else>{{ msg.content }} <a :href="msg.url" :download="msg.filename" style="color: blue; text-decoration: underline;">{{ msg.filename }}</a></template></p><p style="font-size: 0.85em; color: #888;">{{ formatDate(msg.timestamp) }}</p></el-card></div></el-col></el-row><el-row><el-col :span="18"><el-input placeholder="输入消息..." v-model="newMessage" @keyup.enter.native="sendMessage"></el-input></el-col><el-col :span="6"><el-button type="primary" icon="el-icon-send" @click="sendMessage">发送</el-button></el-col></el-row><el-row style="margin-top: 20px;"><el-col :span="18"><el-uploadclass="upload-demo"dragaction="":auto-upload="false":on-change="handleFileChange":file-list="fileList"><i class="el-icon-upload"></i><div class="el-upload__text">拖拽文件到此或点击上传</div></el-upload></el-col><el-col :span="6"><el-button type="success" icon="el-icon-upload2" @click="sendFile">发送文件</el-button></el-col></el-row></el-main></el-container></div><script>new Vue({el: '#app',data() {return {ws: null,users: [],selectedUser: null,currentUser: null,newMessage: '',messages: [],fileList: [],pendingFileMessages: [] // 用于存储尚未处理的文件元数据};},mounted() {this.currentUser = prompt("请输入您的用户名:");this.ws = new WebSocket("ws://192.168.186.77:8081");this.ws.onopen = () => {const initMessage = {type: "init",username: this.currentUser};this.ws.send(JSON.stringify(initMessage));};this.ws.onmessage = (event) => {try {const data = JSON.parse(event.data);if (data.type === 'user_list') {this.users = data.users.filter(user => user !== this.currentUser);} else if (data.type === 'message' || data.type === 'metadata') {data.timestamp = new Date();if (data.type === 'metadata') {this.pendingFileMessages.push(data); // 存储文件元数据} else {this.messages.push(data);}}} catch (error) {// 如果解析失败,可能是Blob数据if (event.data instanceof Blob) {this.handleFileData(event.data);} else {console.error("消息解析失败:", error);}}};},methods: {sendMessage() {if (this.newMessage.trim() && this.selectedUser) {const message = {type: "message",sender: this.currentUser,target: this.selectedUser,content: this.newMessage,timestamp: new Date() // 增加时间戳};this.ws.send(JSON.stringify(message));this.messages.push(message);this.newMessage = '';}},handleFileChange(file, fileList) {this.fileList = fileList;},sendFile() {if (this.fileList.length && this.selectedUser) {const file = this.fileList[0].raw;const reader = new FileReader();reader.onload = (event) => {const metadata = {type: "metadata",sender: this.currentUser,target: this.selectedUser,filename: file.name,filesize: file.size,timestamp: new Date().toISOString() // 增加时间戳};this.ws.send(JSON.stringify(metadata));// 立即显示文件信息const message = {sender: this.currentUser,content: ``,isImage: this.isImageFile(file.name),url: this.isImageFile(file.name) ? URL.createObjectURL(file) : '',filename: file.name, // 保存文件名timestamp: new Date() // 增加时间戳};this.messages.push(message);this.ws.send(event.target.result);};reader.readAsArrayBuffer(file);this.fileList = [];}},handleFileData(blobData) {// 处理文件数据时,检查是否有待处理的文件元数据if (this.pendingFileMessages.length > 0) {const metadata = this.pendingFileMessages.shift(); // 取出第一个元数据const url = URL.createObjectURL(blobData);const lastMessage = {sender: metadata.sender,content: ``,isImage: this.isImageFile(metadata.filename),url: url,filename: metadata.filename, // 保存文件名timestamp: metadata.timestamp};// 更新消息中的图片URL或生成下载链接if (lastMessage.isImage) {lastMessage.content = ``;} else {lastMessage.content = ``;}this.messages.push(lastMessage); // 将消息加入消息列表} else {console.error("未找到合适的文件元数据来处理文件数据。");}},isImageFile(filename) {return /\.(jpeg|jpg|gif|png|svg)$/i.test(filename);},formatDate(date) {const d = new Date(date);const year = d.getFullYear();const month = ('0' + (d.getMonth() + 1)).slice(-2);const day = ('0' + d.getDate()).slice(-2);const hours = ('0' + d.getHours()).slice(-2);const minutes = ('0' + d.getMinutes()).slice(-2);const seconds = ('0' + d.getSeconds()).slice(-2);return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;}}});</script><style>.chatbox {height: 300px;overflow-y: scroll;border: 1px solid #ddd;padding: 10px;margin-bottom: 20px;}.el-upload__input {display: none !important;}</style>
</body>
</html>

8. 测试验证

8.1 启动项目

cmake ./
make
./c_web -c ./config.json

在这里插入图片描述

说明:如果你想结束,请查询8081的PID,进行端口查杀kill -9 PID。

8.2 测试准备

访问:http://192.168.186.77:8080/

注意:IPv4需要切换为你本机IP。

在这里插入图片描述

说明:模拟用户数量:2,本案例是:admin和guest。

在这里插入图片描述

说明:聊天之前,先选择用户。

8.3 实时聊天

在这里插入图片描述

说明:左边是guest用户,右边是admin用户。

8.4 文件传输

在这里插入图片描述

说明:guest发送了一张图片给admin用户。

在这里插入图片描述

说明:admin发送了一个docx文件给guest。

在这里插入图片描述

说明:用户点击链接可以进行下载,下载不安全的原因是因为这是一个http而不是https。控制台描述:192.168.186.77/:1 The file at ‘blob:http://192.168.186.77:8080/997dc48a-83c2-4992-8ad3-960e7a51e74f’ was loaded over an insecure connection. This file should be served over HTTPS.

9. 总结

​ 只是实现了简单的实时聊天和文件传输,并没有严格的会话窗口区分,比如说如果A发送消息给B,C又发送给B,那么B窗口会同时显示A和C的消息,基于Booster库的Websocket实现简单案例。

相关文章:

高性能的 C++ Web 开发框架 CPPCMS + WebSocket 模拟实现聊天与文件传输案例。

1. 项目结构 2. config.json {"service": {"api": "http","port": 8080,"ip": "0.0.0.0"},"http": {"script": "","static": "/static"} }3. CMakeLists.txt…...

合合信息OCR支持30类国内常见票据一站式分类识别,支持医疗发票、数电票识别

合合信息TextIn平台明星产品——国内通用票据识别&#xff0c;重磅更新&#xff01; 产品支持票据类型扩展到23大类、30小类&#xff0c;覆盖场景更全面&#xff0c;同时升级优化了多款票据识别模型&#xff0c;平均识别率较前版本提升11.5%&#xff0c;整体识别速度提升21.9%…...

LeetCode-day40-3151. 特殊数组 I

LeetCode-day40-3151. 特殊数组 I 题目描述示例示例1&#xff1a;示例2&#xff1a;示例3&#xff1a; 思路代码 题目描述 如果数组的每一对相邻元素都是两个奇偶性不同的数字&#xff0c;则该数组被认为是一个 特殊数组 。 Aging 有一个整数数组 nums。如果 nums 是一个 特殊…...

技术研究:Redis 数据结构与 I/O 模型

数据结构 Redis之所以“快”&#xff0c;一方面因为它是内存数据库&#xff0c;所有操作都在内存上完成&#xff0c;内存的访问速度本来就快。另一方面则是因为高效的数据结构&#xff0c;使得操作键值效率较高。总体来说&#xff0c;Redis使用了一个用来保存每个Key/Value的全…...

46-扇孔的处理及铺铜以及布线

1.先连信号线 2.电源管脚,以如下方式处理&#xff1a; 引线打孔处理...

LVS实验的三模式总结

文章目录 LVS的概念叙述NAT工作模式实战案例**思想&#xff1a;**NAT工作模式的优点NAT工作模式的缺点 NAT工作模式的应用场景大致配置 route&#xff1a;打开路由内核功能 部署DR模式集群案例工作思想&#xff1a;大致工作图如下思路模型 具体配置与事实步骤补充 防火墙标签解…...

游戏安全入门-扫雷分析远程线程注入

前言 无论学习什么&#xff0c;首先&#xff0c;我们应该有个目标&#xff0c;那么入门windows游戏安全&#xff0c;脑海中浮现出来的一个游戏 – 扫雷&#xff0c;一款家喻户晓的游戏&#xff0c;虽然已经被大家分析的不能再透了&#xff0c;但是我觉得自己去分析一下还是极好…...

bert-base-chinese模型的完整训练、推理和一些思考

前言 使用google-bert/bert-base-chinese模型进行中文文本分类任务&#xff0c;使用THUCNews中文数据集进行训练&#xff0c;训练完成后&#xff0c;可以导出模型&#xff0c;进行预测。 项目详细介绍和数据下载 数据集下载地址 Github完整代码 现记录训练过程中的一些感悟…...

JS基础5(JS的作用域和JS预解析)

JS的作用域 1. 全局作用域 全局作用域是在代码的任何地方都能访问到的最外层作用域。在浏览器环境下&#xff0c;全局作用域就是window对象&#xff0c;因此所有在全局作用域中声明的变量和函数都会成为window对象的属性和方法。 var globalVar "I am global"; …...

Doris 夺命 30 连问!(中)

导言 抱歉&#xff0c;作为从 S2 开始的骨灰级玩家看到 EDGUZI 官宣首发上线&#xff0c;兴奋之余忘了写文档 - -||&#xff0c;还望各位看官老爷见谅&#xff0c;这次错了&#xff0c;下次还敢 ^_^ 这是继上次的 30 问上篇的中篇&#xff0c;也是 10 个问题&#xff0c;有些…...

书生.浦江大模型实战训练营——(四)书生·浦语大模型全链路开源开放体系

最近在学习书生.浦江大模型实战训练营&#xff0c;所有课程都免费&#xff0c;以关卡的形式学习&#xff0c;也比较有意思&#xff0c;提供免费的算力实战&#xff0c;真的很不错&#xff08;无广&#xff09;&#xff01;欢迎大家一起学习&#xff0c;打开LLM探索大门&#xf…...

SpringBoot 整合 RabbitMQ 实现延迟消息

一、业务场景说明 用于解决用户下单以后&#xff0c;订单超时如何取消订单的问题。 用户进行下单操作&#xff08;会有锁定商品库存、使用优惠券、积分一系列的操作&#xff09;&#xff1b;生成订单&#xff0c;获取订单的id&#xff1b;获取到设置的订单超时时间&#xff0…...

Cilium:基于开源 eBPF 的网络、安全性和可观察性

基于 eBPF 的网络、安全性和可观察性 Cilium 是一种开源的云原生解决方案&#xff0c;它利用 Linux 内核中的 eBPF 技术来提供、保护和监控工作负载之间的网络连接。 什么是 eBPF&#xff1f; eBPF 是一项源自 Linux 内核的技术&#xff0c;允许沙盒程序在特权上下文&#x…...

Axios 详解与使用指南

Axios 详解与使用指南 1. Axios 简介 Axios 是一个基于 Promise 的 HTTP 客户端&#xff0c;能够在浏览器和 Node.js 环境中运行。它提供了一种简便的方式来执行 HTTP 请求&#xff0c;并支持多种请求方法&#xff0c;如 GET、POST、PUT、DELETE 等。Axios 的配置灵活&#x…...

深度学习 —— 个人学习笔记20(转置卷积、全卷积网络)

声明 本文章为个人学习使用&#xff0c;版面观感若有不适请谅解&#xff0c;文中知识仅代表个人观点&#xff0c;若出现错误&#xff0c;欢迎各位批评指正。 三十九、转置卷积 import torch from torch import nndef trans_conv(X, K):h, w K.shapeY torch.zeros((X.shape[…...

解决Mac系统Python3.12版本pip安装报错error: externally-managed-environment的问题

遇到的问题 在Mac安装了Python3.12.x版本&#xff08;3.12.3、3.12.4&#xff09;后&#xff0c;当尝试pip3 install xxx的时候&#xff0c;总是报错&#xff1a;error: externally-managed-environment error: externally-managed-environment This environment is external…...

lvm知识终结

、什么是 LVM LVM 是 Linux 下对磁盘分区进行管理的一种工具&#xff0c;适合管理大存储设备&#xff0c;并允许用户动态调整文件系统的大小 lvm 常用的命令 功能 PV 管理命令 VG 管理命令 LV 管理命令 scan 扫描 pvscan vgscan lvscan create 创建 pvcreate v…...

ESP32S3 IDF 对 16路输入输出芯片MCP23017做了个简单的测试

这次还是使用了idf老版本4.4.7&#xff0c;上次用了5.3&#xff0c;感觉不好用&#xff0c;官方的MCP23017芯片是英文版&#xff0c;真的很难读明白&#xff0c;可能是我英语水平不够吧。先看看每个寄存器的功能&#xff1a; IODIRA 和 IODIRB: 输入/输出方向寄存器 IPOLA 和 I…...

【技术前沿】Flux.1部署教程入门--Stable Diffusion团队最前沿、免费的开源AI图像生成器

项目简介 FLUX.1 是一种新的开源图像生成模型。它由 Stable Diffusion 背后的团队 Black Forest Labs 开发。 官网中有以下功能开源供大家参考&#xff1a; FLUX.1 擅长在图像中准确再现文字&#xff0c;因此非常适合需要清晰文字或短语的设计。无论是标牌、书籍封面还是品牌…...

Redis 的 STREAM 和 RocketMQ 是两种不同的消息队列和流处理解决方案,它们在设计理念、功能和用途上有显著区别。以下是它们的主要区别:

20240813 Redis 的 STREAM 和 RocketMQ 是两种不同的消息队列和流处理解决方案&#xff0c;它们在设计理念、功能和用途上有显著区别。以下是它们的主要区别&#xff1a;1. 使用 Redis 的 Sorted Set 数据结构连接到 Redis示例用法添加事件获取滑动窗口内的事件移除过期事件连接…...

Visual Studio Code安装与C/C++语言运行(上)

Visual Studio Code&#xff08;VS Code&#xff09;作为微软开发的一款轻量级但功能强大的源代码编辑器&#xff0c;广泛应用于各种编程语言的开发&#xff0c;包括C/C。以下将详细介绍VS Code的安装过程以及与C/C语言运行环境的配置。 一、Visual Studio Code的安装 1. 准备…...

探索数据可视化,数据看板在各行业中的应用

数据可视化是一种通过图形化手段将数据呈现出来的技术&#xff0c;它将复杂的数据和信息转化为易于理解的图表、地图、仪表盘等视觉元素&#xff0c;使得数据的模式、趋势和关系更加直观地展现出来。通过数据可视化&#xff0c;用户可以快速识别重要信息、发现潜在问题&#xf…...

haralyzer 半自动,一次性少量数据采集快捷方法

使用场景&#xff1a;半自动&#xff0c;一次性少量数据采集需求在工作中还是不少遇到的&#xff0c;无论使用模拟的方式&#xff0c;或者破解都不太划算。其实这种需求&#xff0c;使用半自动爬虫是最简单的。不需要考虑网站反爬虫的问题&#xff0c;因为你使用的就是真实的浏…...

mall-admin-web-master前端项目下载依赖失败解决

碰壁后的总结 pythone 环境 2.XX版本&#xff0c;切记不要3.0以上的。node 16.x不能太高 错误案例 npm ERR! code 1 npm ERR! path D:\workspace\springBootMall\mall-admin-web-master\node_modules\node-sass npm ERR! command failed npm ERR! command C:\windows\system…...

【07】JVM是怎么实现invokedynamic的

在Java中&#xff0c;方法调用会被编译为invokeStatic&#xff0c;invokeSpecial&#xff0c;invokVirtual以及invokeInterface四种指令。这些指令与包含目标方法类名、方法名以及方法描述符的符号引用捆绑&#xff0c;在实际运行之前&#xff0c;JVM根据这个符号引用链接到具体…...

使用API有效率地管理Dynadot域名,查看参与的拍卖列表

前言 Dynadot是通过ICANN认证的域名注册商&#xff0c;自2002年成立以来&#xff0c;服务于全球108个国家和地区的客户&#xff0c;为数以万计的客户提供简洁&#xff0c;优惠&#xff0c;安全的域名注册以及管理服务。 Dynadot平台操作教程索引&#xff08;包括域名邮箱&…...

Linux 基本指令讲解

linux 基本指令 clear 清屏 Alt Enter 全屏/退出全屏 pwd 显示当前用户所处路径 cd 改变目录 cd /root/mikecd … 返回上级目录cd - 返回最近所处的路径cd ~ 直接返回当前用户自己的家目 roor 中&#xff1a;/root普通用户中&#xff1a;/home/mike mkdir 创建一个文件夹(d) …...

PRE_EMPHASIS

PRE_EMPASIS属性用于提高高频信号的信号完整性 其通过传输线遭受高频损耗。发射机 预加重&#xff08;pre_EMPASIS&#xff09;功能允许对某些信号驱动器进行预加重 I/O标准。 提示&#xff1a;发射机的预加重可以与接收机的均衡相结合&#xff0c;以提高 整体信号完整性。 理想…...

【QT常用技术讲解】多线程处理+全局变量处理异步事件并获取多个线程返回的结果

前言 QTableView加入勾选项后&#xff08;参考【QT常用技术讲解】QTableView添加QCheckBox、QPushButton&#xff09;&#xff0c;如果支持右键菜单功能&#xff0c;此时就有统一执行多个异步事件&#xff0c;并且统一输出到界面的需求了&#xff0c;本篇结合多线程共享全局变量…...

数组列表中的最大距离

给定 m 个数组&#xff0c;每个数组都已经按照升序排好序了。现在你需要从两个不同的数组中选择两个整数&#xff08;每个数组选一个&#xff09;并且计算它们的距离。两个整数 a 和 b 之间的距离定义为它们差的绝对值 |a-b| 。你的任务就是去找到最大距离 示例 1&#xff1a;…...