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 中的多线程编程和并发控制,包括线程的创建、同步…...
提供10个mysql的实例和思路
学生信息管理系统 学生表(id, name, gender, age, class_id)班级表(id, name)思路:通过学生表和班级表进行关联,可以实现学生信息的查询、添加、修改、删除等操作。 订单管理系统 订单表(id, us…...
FPGA项目(14)——基于FPGA的数字秒表设计
1.功能设计 设计内容及要求: 1.秒表最大计时范围为99分59. 99秒 2.6位数码管显示,分辨率为0.01秒 3.具有清零、启动计时、暂停及继续计时等功能 4.控制操作按键不超过二个。 2.设计思路 所采用的时钟为50M,先对时钟进行分频,得到100HZ频率…...
浅谈指数移动平均(ema)
经常在各种代码中看到指数移动平均(比如我专注的网络传输领域),但却不曾想到它就是诠释世界的方法,我们每个人都在被这种方式 “平均”… 今天说说指数移动平均(或移动指数平均,Exponential Moving Average)。 能查到的资料都侧重于其数学形…...
1-并发编程线程基础
什么是线程 在讨论什么是线程前有必要先说下什么是进程,因为线程是进程中的一个实体,线程本身是不会独立存在的。 进程是代码在数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,线程则是进程的一个执行路径&#…...
vue中动态出来返回的时间秒数,在多少范围显示多少秒,多少范围显示分,小时等等
在Vue中,你可以使用计算属性(computed property)或过滤器(filter)来根据动态返回的时间秒数来显示不同的时间单位,比如秒、分、小时等等。 下面是一个使用计算属性的示例: <template>&l…...
English: go through customs
文章目录 常见单词机场指示登机和中转降落以及公共服务签证篇出/入境卡篇入境英语会话篇 常见单词 customs: 海关 (kʌstəmz)cash: 现金 (kʃ)passport: 护照 (pspɔːt)luggage/baggage: 行李 (lʌɡɪdʒ/ˈbɡɪdʒ)Exchange: 换钱 (ɪks’tʃeɪndʒ)airport: 飞机场 (ɛ…...
Nginx 多端口部署多站点
目录 1.进行nginx.conf 2.复制粘贴 3.修改端口及站点根目录 4. 网站上传 1.进行nginx.conf 在 nginx 主要配置文件 nginx.conf 中,server 是负责一个网站配置的,我们想要多个端口访问的话,可以复制多个 server 先进入到 nginx.conf 中 …...
从零开始配置kali2023环境:配置jupyter的多内核环境
在kali2023上面尝试用anaconda3,anaconda2安装实现配置jupyter的多内核环境时出现各种问题,现在可以通过镜像方式解决 1. 搜索镜像 ┌──(holyeyes㉿kali2023)-[~] └─$ sudo docker search anaconda ┌──(holyeyes㉿kali2023)-[~] └─$ sudo …...
Dart调用JS对10000条定位数据滤波
使用Dart调用JS,还是为了练习跨语言调用; 一、编写对应的JS代码 平时在开发时不推荐将算法放在JS里,我这里是简单的做一下数据过滤; 首先生成一些随机定位数据,在实际开发中可以使用真实数据; // 随机定…...
大模型应用实践:AIGC探索之旅
随着OpenAI推出ChatGPT,AIGC迎来了前所未有的发展机遇。大模型技术已经不仅仅是技术趋势,而是深刻地塑造着我们交流、工作和思考的方式。 本文介绍了笔者理解的大模型和AIGC的密切联系,从历史沿革到实际应用案例,再到面临的技术挑…...
建什么类型个人网站比较好/前端性能优化
工作中会经常遇到这样的业务问题:如果找到每个类别下用户点击最多的5个商品是什么?这类问题其实就是常见的:每组最大的N条记录(topN)。【题目】现有“成绩表”,记录了每个学生各科的成绩。表内容如下:问题:…...
网站教程网/百度指数总结
MapReduce编程模型 【1】先对输入的信息进行切片处理。 【2】每个map函数对所划分的数据并行处理,产生不同的中间结果输出。 【3】对map的中间结果数据进行收集整理(aggregate & shuffle)处理,交给reduce。 【4】reduce进行计…...
那个网站做排列五头比较准/做了5天游戏推广被抓了
kubesphere删除节点 停止调度节点 将节点标记为不可调度可以防止调度程序将新的Pod放置到该节点上,同时不会影响该节点上现有pod。 以admin身份登录控制台,访问【集群管理】页面。若要将节点标记为不可调度,从左侧菜单中选择【节点】下的【…...
资源类网站怎么做/青岛seo网络推广
引言如何提交首先开启IDEA版本控制集成查看并连接仓库共享目录提交代码SVN 默认目录附录总结如何使用idea将代码提交至SVN引言前面我们说了如何在本地搭建 svn 服务器,小伙伴们都肯定已经亲身搭建完成了,那搭建好了以后我们在日常开发中如何更方便快捷的…...
邯郸专业做网站报价/查关键词热度的网站
在实际的开发过程中,我们经常需要用到缓存。使用缓存常见的一个场景就是key不在缓存中,这个时候我们会去读取这个key对应的值,然后把这个值放到缓存中,代码如下: public class CacheNoFuture {private ConcurrentHashM…...
wordpress提示没有/体验式营销经典案例
给%JAVA_HOME%\bin前面增加英文的点和分号 “.;”...