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页了,如果下载目录还有图片,则可通过curlwget下载:

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的文件都缓存内存,后续客户下载文件,就直接从内存发数据,不会走文件流,多个连接请求同一文件也是零拷贝,效率很高.

因为是静态文件服务器,如果目录添加新的文件,需要重启一下服务器.

yalantinglibscoro_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_serverstruct_json,只需要数十行代码,就实现了一个简易的聊天室服务端.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/599989.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

深入理解Python中的二分查找与bisect模块

&#x1f497;&#x1f497;&#x1f497;欢迎来到我的博客&#xff0c;你将找到有关如何使用技术解决问题的文章&#xff0c;也会找到某个技术的学习路线。无论你是何种职业&#xff0c;我都希望我的博客对你有所帮助。最后不要忘记订阅我的博客以获取最新文章&#xff0c;也欢…

安装Cygwin的包管理器apt-cyg并安装tree命令

文章目录 一、从官网添加必要软件包1. 安装2. 检查 二、安装apt-cyg1. 下载安装2.修复 三、安装tree命令1. 安装2.检验 一、从官网添加必要软件包 1. 安装 因为第一次安装cygwin时走的都是默认选项&#xff0c;所以这里是二次添加额外包。 打开官网&#xff0c;下载安装程序。…

【导出与导入Virtualbox虚拟机和启动连接openGauss数据库】

【导出与导入Virtualbox虚拟机和启动连接openGauss数据库】 一、导出虚拟机二、导入虚拟机三、启动数据库四、使用Data Studio连接数据库 一、导出虚拟机 选择关机状态的虚拟机 -> 管理菜单 -> 导出虚拟电脑 点击完成后&#xff0c;需要等待一小段时间&#xff0c;如…

JS实现/封装节流函数

封装节流函数 节流原理&#xff1a;在一定时间内&#xff0c;只能触发一次 let timer, flag; /*** 节流原理&#xff1a;在一定时间内&#xff0c;只能触发一次* * param {Function} func 要执行的回调函数 * param {Number} wait 延时的时间* param {Boolean} immediate 是否立…

每日一道算法题day-three(备战蓝桥杯)

哈喽大家好&#xff0c;今天来给大家带来每日一道算法题系列第三天&#xff0c;让我们来看看今天的题目&#xff0c;一起备战蓝桥杯 题目&#xff1a; 小 Y的桌子上放着 n 个苹果从左到右排成一列&#xff0c;编号为从 11 到 n。 小苞是小 Y 的好朋友&#xff0c;每天她都会…

HAproxy群集

HAproxy群集 常见的集群调度器HAproxy 、nginx、LVS区别HAproxynginxlvs HAproxy介绍HAproxy特点HAproxy常见的负载均衡策略HAproxy会话保持HAproxy配置实例 常见的集群调度器 常见的web集群调度器分为软件和硬件 软件&#xff1a;LVS Haproxy nginx 硬件&#xff1a; F5 Ar…

Java JDK8到21演升特性汇总

Java JDK 8 到 19 演升特性汇总 文章目录 Java JDK 8 到 19 演升特性汇总一、版本roadmap图二、版本与特性JDK8 [2014-03-18]JDK11[2018-09-25]JDK17【2021-09-14】JDK21 [2023-09-19] 一、版本roadmap图 官方地址 JDK8,JDK11,JDK17,JDK21是长期维护的版本。spring boot3最低支…

D-Link DES-108 交换机

D-Link DES-108 交换机 1. 百兆交换机 8 口References ​ D-Link Corporation is a Taiwanese multinational networking equipment manufacturing corporation headquartered in Taipei, Taiwan. Taiwanese&#xff1a;adj. 台湾的 n. 台湾人 headquarter [hedkwɔ:tə]&#…

汽车电子学习总结

国内的主要有比亚迪、联合汽车电子&#xff08;联电&#xff09;、麦格米特、上海电驱动&#xff1b;国外的主要有欧美系的博世、麦格纳、大陆、博格华纳&#xff1b;日系的电装、电产等公司。

AIOps探索 | 基于大模型构建高效的运维知识及智能问答平台(2)案例分享

原作者&#xff1a;擎创科技产品专家 布博士 案例分享 所需要的软件列表 本次案例的实现&#xff0c;全部采用开源或SAAS的产品来提供&#xff0c;并不涉及到私有化部署的软件产品。软件列表如下所示&#xff0c;如何申请apikey请自行研究&#xff0c;在这里不再详细说明&…

VIT用于图像分类 学习笔记(附代码)

论文地址&#xff1a;https://arxiv.org/abs/2010.11929 代码地址&#xff1a;https://github.com/bubbliiiing/classification-pytorch 1.是什么&#xff1f; Vision Transformer&#xff08;VIT&#xff09;是一种基于Transformer架构的图像分类模型。它将图像分割成一系列…

Python-实现高并发的常见方式

高并发能帮支持快速处理大量执行任务&#xff0c;提高代码的执行效率&#xff0c;以下是在日常开发中常见的高并发方式 多线程&#xff08;Threading&#xff09; Python 的 threading 模块可以非常容易地创建和管理线程。线程共享内存空间&#xff0c;这意味着它们可以更高效的…

JS tostring()和join()方法

在JavaScript中&#xff0c;toString()和join()都是用于处理数组的方法。它们的功能和用法如下&#xff1a; 1.toString()方法&#xff1a; toString()方法将数组转换为一个由每个元素字符串形式拼接而成的字符串。该方法不会改变原始数组&#xff0c;而是返回一个新的字符串。…

如何实现安卓端与苹果端互通

在移动应用开发中&#xff0c;如何实现安卓端和苹果端的互通是一个重要的问题。二者缺少一个都会有损失&#xff0c;那如何实现安卓端跟苹果端互通&#xff0c;下面简单的介绍几点方法来帮助你再不同的平台上实现数据交互和功能互通。 基于Web技术 使用Web技术是一种常见并且…

构建可伸缩和高性能系统的设计原则和最佳实践

在当今快节奏的软件开发环境中&#xff0c;构建可伸缩和高性能的系统对于满足用户需求至关重要。采用设计原则和最佳实践是确保系统具备良好性能和可扩展性的关键。本文将介绍一些构建可伸缩和高性能系统的设计原则和最佳实践。 1. 分布式架构 采用分布式系统架构&#xff0c…

数字孪生与大数据和分析技术的结合

数字孪生与大数据和分析技术的结合可以为系统提供更深入的见解、支持实时决策&#xff0c;并优化模型的性能。以下是数字孪生在大数据和分析技术中的一些应用&#xff0c;希望对大家有所帮助。北京木奇移动技术有限公司&#xff0c;专业的软件外包开发公司&#xff0c;欢迎交流…

2024阿里云服务器配置推荐方案

阿里云服务器配置怎么选择合适&#xff1f;CPU内存、公网带宽和ECS实例规格怎么选择合适&#xff1f;阿里云服务器网aliyunfuwuqi.com建议根据实际使用场景选择&#xff0c;例如企业网站后台、自建数据库、企业OA、ERP等办公系统、线下IDC直接映射、高性能计算和大游戏并发&…

美年大健康黄伟:从选型到迁移,一个月升级核心数据库

核心生产系统的数据库&#xff0c;从接到替换需求到完成分布式升级&#xff0c;需要多久&#xff1f;一个月&#xff0c;这是美年大健康的回答。一个月集中调配各种资源&#xff0c;美年大健康完成了应用程序基本零改造的平滑迁移&#xff0c;新数据库在成本更低的前提下&#…

迪拜公司注册优势 迪拜公司注册条件 迪拜公司注册流程

迪拜作为阿 拉伯联合酋长国&#xff08;United Arab Emirates&#xff0c;简称UAE&#xff09;的一个城市&#xff0c;拥有独特的优势和吸引力。以下是迪拜公司注册的优势、条件和流程&#xff1a; 迪拜公司注册优势 1、无外汇管制&#xff1a;在迪拜注册的公司可以自 由转移资…

2023-RunwayML-Gen-2 AI视频生成功能发展历程

RunwayML是一个人工智能工具&#xff0c;它为设计师、艺术家和创意人士提供了一种简单的方式来探索和应用机器学习技术。 RunwayML官方网页地址&#xff1a;Runway - Advancing creativity with artificial intelligence. RunwayML专区RunwayML-喜好儿aigcRunwayML 是一种先进…