2401C++,实现文件服务器和聊天室
文件服务器
使用yalantinglibs
,几行代码
开发静态文件服务器
最近的workshop
上的一个任务
,就是实现一个文件服务器
,只要设置下载目录
之后,就可下载
目录里面的文件.
看看用yalantinglibs
怎么实现一个静态文件服务器
的吧.
coro_http::coro_http_server server(1, 9001);
server.set_static_res_dir("download", "");
server.sync_start();
在浏览器
输入http://127.0.0.1:9001/download/index.html
就能打开index.html
页了,如果下载目录
还有图片,则可通过curl
或wget
下载:
curl -O http://127.0.0.1:9001/download/test.jpg
wget http://127.0.0.1:9001/download/test.jpg
set_static_res_dir
函数有两个
参数,第一个
参数是设置
虚目录,第二个
参数设置
实际文件目录
,如果设置
为空,则当前目录
就是下载文件目录
.
如果想控制
每次往客户
发送的数据流大小
,则可通过server.set_transfer_chunked_size(chunk_size)
来设置.
小文件下载优化
如果需要高并发
下载海量小文件
,每次都打开文件
读文件流
,发送
完关闭
文件,会导致性能瓶颈
,此时可启用缓存
,在内存中缓存
小文件,之后请求文件
就省掉了打开和关闭文件
的步骤
了.
缓存文件
也是非常简单
的,一个函数
搞定.
coro_http::coro_http_server server(1, 9001);
server.set_static_res_dir("download", "");
server.set_max_size_of_cache_files(100*1204);
//缓存
server.sync_start();
set_max_size_of_cache_files
函数设置后,会把下载目录
里面所有文件大小
小于100k
的文件都缓存
到内存
,后续客户
下载文件,就直接从内存
发数据,不会走文件流
,多个连接请求
同一文件也是零拷贝
,效率很高.
因为是静态文件服务器
,如果目录添加
了新的文件
,需要重启一下服务器
.
用yalantinglibs
的coro_http::coro_http_server
实现的静态文件
服务器,不仅可做一个文件服务器
,也可做一个静态
的网站页,还是很方便
的,不妨试试.
原文
聊天室
基于websocket
的实现,服务端
使用yalantinglibs.coro_http_server
,前端页
使用html+js
实现.
一个聊天室
有以下基本功能
:
1,登录/登出
2,更新用户列表
3,发送消息
4,登录,登出和更新
用户列表
登录
时,需要填一个用户名
,填好
用户名之后,js websocket client
发起连接
,当连接
成功之后,把用户名
发送到服务端
,服务端
要把登录
用户名广播
给聊天室的其它成员
,其它成员
收到新加入
用户消息后,要更新用户列表
,把新加入
用户添加到用户列表
中.
登出
时,同样要更新列表
,把登出
的人从列表
中删掉.
发送消息功能
聊天室用户发送一条消息,需要通过服务端
广播给所有成员
.
先看看前端登录
部分的代码:
var uname = prompt('请输入用户名', 'user' + uuid(8, 16));
var ws = new WebSocket("ws://127.0.0.1:9001/");
ws.onopen = function () {var data = "系统消息:创建连接成功";let user_info = { 'type': 'login', 'content': uname };sendMsg(user_info);
};function sendMsg(msg) {var data = JSON.stringify(msg);ws.send(data);
}
前端和服务端
创建websocket
连接之后,把消息类型和用户名
序化成一个json
串,再发送
到服务端.
服务端
如何处理登录消息
呢?
//定义`json`结构
//登录/登出的`json`结构
struct login_info_t {std::string_view type;std::string_view content;std::vector<std::string> user_list;
};
REFLECTION(login_info_t, type, content, user_list);
using logout_info_t = login_info_t;
//发送给前端的`json`结构
struct user_info_t {std::string_view type;std::string_view from;std::string_view content;
};
REFLECTION(user_info_t, type, from, content);
//收到前端消息的`json`结构
struct message_t {std::string type;std::string_view content;
};
REFLECTION(message_t, type, content);
int main() {coro_http::coro_http_server server(1, 9001);server.set_static_res_dir("", "");std::mutex mtx;std::unordered_map<intptr_t, std::string> conn_map;server.set_http_handler<cinatra::GET>("/",[&](coro_http_request &req,coro_http_response &resp) -> async_simple::coro::Lazy<void> {websocket_result result{};std::unordered_map<intptr_t, std::string> map;std::string resp_str;while (true) {result = co_await req.get_conn()->read_websocket();message_t msg{};struct_json::from_json(msg, result.data);if (msg.type == "login") {std::string user_name;{std::scoped_lock lock(mtx);if (msg.type == "login") {user_name = std::string{msg.content};conn_map.emplace((intptr_t)req.get_conn(), user_name);}map = conn_map;}if (!map.empty()) {std::vector<std::string> user_list;std::transform(map.begin(), map.end(), std::back_inserter(user_list), [](auto &kv) { return kv.second; });logout_info_t info{msg.type, user_name, std::move(user_list)};struct_json::to_json(info, resp_str);}}co_await broadcast(map, resp_str);}});server.sync_start();
}
服务端
读到websocket
消息后,先反序化json
串,得到消息类型和消息内容
,如果是login
消息则把链接指针和用户名
保存到表示聊天室
用户列表的map
中,后面更新用户列表和广播消息
都需要该map
.
更新map
之后,会把map
中所有的value
放到一个vector
中,得到一个用户名列表
,接着生成一个json
格式的消息,消息类型是login
,消息内容
是用户列表
.
最后通过broadcast
广播消息.
注意该map
需要加锁
,用户登录和登出
都需要更新,该map
.
登出
逻辑是类似的,只不过需要从map
里移除用户.
广播消息
async_simple::coro::Lazy<void> broadcast(auto &conn_map, std::string &resp_str) {for (auto &[conn_ptr, user_name] : conn_map) {auto conn = (coro_http_connection *)conn_ptr;auto ec = co_await conn->write_websocket(resp_str);if (ec) {std::cout << ec.message() << "\n";continue;}}resp_str.clear();
}
广播消息
很简单,遍历map
,发送消息
即可.这里也可用collectAll
并行发送.
处理用户发送的消息
if (msg.type == "user") {std::string from;{std::scoped_lock lock(mtx);from = conn_map.at((intptr_t)req.get_conn());map = conn_map;}user_info_t info{msg.type, from, msg.content};struct_json::to_json(info, resp_str);
}
co_await broadcast(map, resp_str);
把消息类型,谁发的消息和消息内容
等json
化然后广播
出去即可.
前端处理广播消息
ws.onmessage = function (e) {var msg = JSON.parse(e.data);var sender, user_name, name_list, change_type;switch (msg.type) {case 'user':sender = '<b style="color:green;">' + msg.from + '说: ' + '</b>';break;case 'login':case 'logout':user_name = msg.content;name_list = msg.user_list;change_type = msg.type;dealUser(user_name, change_type, name_list);return;}var data = sender + msg.content;listMsg(data);
};
function listMsg(data) {var msg_list = document.getElementById("msg_list");var msg = document.createElement("p");msg.innerHTML = data;msg_list.appendChild(msg);msg_list.scrollTop = msg_list.scrollHeight;
}
function dealUser(user_name, type, name_list) {var user_list = document.getElementById("user_list");var user_num = document.getElementById("user_num");while (user_list.hasChildNodes()) {user_list.removeChild(user_list.firstChild);}for (var index in name_list) {var user = document.createElement("p");user.innerHTML = name_list[index];user_list.appendChild(user);}user_num.innerHTML = name_list.length;user_list.scrollTop = user_list.scrollHeight;var change = type == 'login' '上线' : '下线';var data = '<b style="color:red;">系统消息</b>: ' + user_name + ' 已' + change;listMsg(data);
}
前端
收到广播消息
之后,在html
页中把发言者
的名字和消息内容
展示出来即可.
收到登录和登出
消息后更新用户列表
.
运行聊天室
先启动服务端
,然后在浏览器
中输入网址:http://127.0.0.1:9001/client.html
就能看到登录聊天室的页了.
当从浏览器
输入该网址
之后,会从服务端
下载client.html
页,而coro_http_server
已设置了静态文件目录
:
server.set_static_res_dir("", "");
可下载
当前目录下的任意静态文件
,而前端
需要下载的是client.html
文件,所以需要确保client.html
文件在当前路径下,否则会返回
一个404
的错误.
完整示例代码在yalantinglibs
里:
服务端:
前端html
yalantinglibs
使用了coro_http_server
和struct_json
,只需要数十行代码
,就实现了一个简易的聊天室服务端
.
相关文章:
2401C++,实现文件服务器和聊天室
文件服务器 使用yalantinglibs,几行代码开发静态文件服务器 最近的workshop上的一个任务,就是实现一个文件服务器,只要设置下载目录之后,就可下载目录里面的文件. 看看用yalantinglibs怎么实现一个静态文件服务器的吧. coro_http::coro_http_server server(1, 9001); server.…...
【ESP-NOW 入门(ESP32 with Arduino IDE)】
ESP-NOW 入门(ESP32 with Arduino IDE) 1. 前言2. Arduino集成开发环境3. ESP-NOW 简介3.1 ESP-NOW 支持以下功能:3.2 ESP-NOW 技术还存在以下局限性:4. ESP-NOW 单向通信4.1 一个 ESP32 开发板向另一个 ESP32 开发板发送数据4.2 一个“主”ESP32 向多个 ESP32“slave”发送…...

PHP序列化总结2--常见的魔术方法
魔术方法的概念 PHP的魔术方法是一种特殊的方法,用于覆盖PHP的默认操作。它们以双下划线(__)开头,后面跟着一些特定的字符串,如__construct()、__destruct()、__get()等。这些魔术方法在对象执行特定操作时被自动调用…...

Docker 入门 ------容器互通以及Dockerfile
1. 端口映射以及容器互联 Docker 除了通过网络访问,还提供了两种很方便的功能来满足服务访问的基本需求: 允许映射容器内应用的服务端口到本地宿主主机互联机制实现多个容器间通过容器名来快速访问 1.1 容器映射实现访问容器 1.1.1 从外部访问容器应…...

AI绘图模型不会写字的难题解决了
介绍 大家好,最近有个开源项目比较有意思,解决了图像中不支持带有中文的问题。 https://github.com/tyxsspa/AnyText。 为什么不能带有中文? 数据集局限 Stable Diffusion的训练数据集以英文数据为主,没有大量包含其他语言文本的…...

vue-cli创建项目时由esLint校验导致报错或警告的问题及解决
vue-cli创建项目时由esLint校验导致报错或警告的问题及解决 一、万能办法 一、万能办法 //就是在报错的JS文件中第一行写上 /* eslint-disable */链接: https://www.yii666.com/blog/288808.html 其它的方法我遇见了再补充...

uniapp:实现手机端APP登录强制更新,从本地服务器下载新的apk更新,并使用WebSocket,实时强制在线用户更新
实现登录即更新,或实时监听更新 本文介绍的是在App打开启动的时候调用更新,点击下方链接,查看使用WebSocket实现实时通知在线用户更新。 uniapp:全局消息是推送,实现app在线更新,WebSocket,ap…...

设计循环队列——oj题622
. 个人主页:晓风飞 专栏:LeetCode刷题|数据结构|Linux 路漫漫其修远兮,吾将上下而求索 文章目录 题目要求:应该支持如下操作:示例:提示: 结构体定义队列的创建基本操作判断队列是否为空…...

阿里后端实习一面面经
阿里后端实习一面面经 项目中使用到了es,es的作用? elasticsearch是一款非常强大的开源搜索引擎,具备非常多强大功能,可以帮助我们从海量数据中快速找到需要的内容 es中的重要概念? 群集:一个或多个节点…...

element-ui组件DatePicker日期选择器移动端兼容
element-ui组件DatePicker日期选择器移动端兼容 css /** 移动端展示 **/ media screen and (max-width: 500px) {.el-picker-panel__sidebar {width: 100%;}.el-picker-panel {width: 400px!important;}.el-picker-panel__content {width: 100%;}.el-picker-panel__body{marg…...

burpsuite 爆破
靶场搭建:phpstudy的安装与靶场搭建 - junlin623 - 博客园 (cnblogs.com) 账号字典:XXTK: 一些弱口令、fuzz字典 (gitee.com) 网盘链接:https://pan.baidu.com/s/1v5pAwaTwoeCnJgkUXf3iLQ?pwd=mllm 提取码:mllm --来自百度网盘超级会员V2的分享 一、暴力破解 - 基于…...

SparkSQL基础解析(三)
1、 Spark SQL概述 1.1什么是Spark SQL Spark SQL是Spark用来处理结构化数据的一个模块,它提供了2个编程抽象:DataFrame和 DataSet,并且作为分布式SQL查询引擎的作用。 我们已经学习了Hive,它是将Hive SQL转换成MapReduce然后提…...

gz-hamonic 安装提示缺少许多依赖无法安装
在软件更新源中增加gz-hamonic的软件源, 点击添加,在输入框中填入如下语句: deb http://packages.osrfoundation.org/ubuntu jammy main 如图所示: 然后执行 sudo apt -get install gz-hamonic即可安装。 如下图 在终端中输入…...
新版Edge卸载
新版Edge卸载:步骤与注意事项 随着Windows 10的发布,微软推出了新版Edge浏览器。虽然新版Edge浏览器具有许多优秀的新功能和改进,但有时您可能希望卸载它并使用其他浏览器。在本文中,我们将向您介绍如何卸载新版Edge浏览器&#…...
Ansibe自动化基础
目录 一.Ansibe自动化概述 1.特点 2.工作特性 3.应用场合 二.ansibe安装即相关文件说明 1.安装 2.相关文件 3.主配置文件内容详解 4.ansibe运行机制 三.ansibe管理节点命令 1.Ansibe 四.主机组配置 1.基本配置 第一种: 第二种: 2.设置SSH…...

2023 年中国高校大数据挑战赛赛题B DNA 存储中的序列聚类与比对-解析与参考代码
题目背景:目前往往需要对测序后的序列进行聚类与比对。其中聚类指的是将测序序列聚类以判断原始序列有多少条,聚类后相同类的序列定义为一个簇。比对则是指在聚类基础上对一个簇内的序列进行比对进而输出一条最有 可能的正确序列。通过聚类与比对将会极大…...

决策树--分类决策树
1、介绍 ① 定义 分类决策树通过树形结构来模拟决策过程,决策树由结点和有向边组成。结点有两种类型:内部结 点和叶结点。内部结点表示一个特征或属性,叶子节点表示一个类。 ② 生成过程 用决策树分类,从根结点开始ÿ…...
【2024/1/5】
2024/1/5周报 本周开展工作下周工作计划 本周开展工作 首先的话就是跟大家汇报一下上一个项目的进度,那因为一些我这边的不可控的因素暂时进行搁置,随后的话还是需要在进行做的。 因此我们最近在做一个web端的项目,这个项目的具体的就不汇报…...

CNN——VGG
1.VGG简介 论文下载地址:https://arxiv.org/pdf/1409.1556.pdf VGGNet 是由牛津大学视觉几何小组(Visual Geometry Group, VGG)提出的一种深层卷积网络结构,他们以 7.32% 的错误率赢得了 2014 年 ILSVRC 分类任务的亚军ÿ…...
深入理解Java中的多线程编程与并发控制
当谈论到 Java 编程语言时,多线程编程和并发控制是其中最重要的话题之一。Java 在多线程领域有着强大的支持和丰富的工具集,允许开发人员利用并发性来提高程序性能和效率。本文将深入探讨 Java 中的多线程编程和并发控制,包括线程的创建、同步…...

未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?
编辑:陈萍萍的公主一点人工一点智能 未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战,在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…...
[2025CVPR]DeepVideo-R1:基于难度感知回归GRPO的视频强化微调框架详解
突破视频大语言模型推理瓶颈,在多个视频基准上实现SOTA性能 一、核心问题与创新亮点 1.1 GRPO在视频任务中的两大挑战 安全措施依赖问题 GRPO使用min和clip函数限制策略更新幅度,导致: 梯度抑制:当新旧策略差异过大时梯度消失收敛困难:策略无法充分优化# 传统GRPO的梯…...

日语AI面试高效通关秘籍:专业解读与青柚面试智能助攻
在如今就业市场竞争日益激烈的背景下,越来越多的求职者将目光投向了日本及中日双语岗位。但是,一场日语面试往往让许多人感到步履维艰。你是否也曾因为面试官抛出的“刁钻问题”而心生畏惧?面对生疏的日语交流环境,即便提前恶补了…...
rknn优化教程(二)
文章目录 1. 前述2. 三方库的封装2.1 xrepo中的库2.2 xrepo之外的库2.2.1 opencv2.2.2 rknnrt2.2.3 spdlog 3. rknn_engine库 1. 前述 OK,开始写第二篇的内容了。这篇博客主要能写一下: 如何给一些三方库按照xmake方式进行封装,供调用如何按…...

华为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…...

高危文件识别的常用算法:原理、应用与企业场景
高危文件识别的常用算法:原理、应用与企业场景 高危文件识别旨在检测可能导致安全威胁的文件,如包含恶意代码、敏感数据或欺诈内容的文档,在企业协同办公环境中(如Teams、Google Workspace)尤为重要。结合大模型技术&…...
【决胜公务员考试】求职OMG——见面课测验1
2025最新版!!!6.8截至答题,大家注意呀! 博主码字不易点个关注吧,祝期末顺利~~ 1.单选题(2分) 下列说法错误的是:( B ) A.选调生属于公务员系统 B.公务员属于事业编 C.选调生有基层锻炼的要求 D…...
CRMEB 框架中 PHP 上传扩展开发:涵盖本地上传及阿里云 OSS、腾讯云 COS、七牛云
目前已有本地上传、阿里云OSS上传、腾讯云COS上传、七牛云上传扩展 扩展入口文件 文件目录 crmeb\services\upload\Upload.php namespace crmeb\services\upload;use crmeb\basic\BaseManager; use think\facade\Config;/*** Class Upload* package crmeb\services\upload* …...
06 Deep learning神经网络编程基础 激活函数 --吴恩达
深度学习激活函数详解 一、核心作用 引入非线性:使神经网络可学习复杂模式控制输出范围:如Sigmoid将输出限制在(0,1)梯度传递:影响反向传播的稳定性二、常见类型及数学表达 Sigmoid σ ( x ) = 1 1 +...
css3笔记 (1) 自用
outline: none 用于移除元素获得焦点时默认的轮廓线 broder:0 用于移除边框 font-size:0 用于设置字体不显示 list-style: none 消除<li> 标签默认样式 margin: xx auto 版心居中 width:100% 通栏 vertical-align 作用于行内元素 / 表格单元格ÿ…...