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的密切联系,从历史沿革到实际应用案例,再到面临的技术挑…...
做跨境的网站/营销软件
前一段写了一篇“使用Windows Mobile 6.5访问Exchange2010邮箱”,看到大家很感兴趣,并有朋友询问如何使用手机版的OC,今天整好有时间,把这段内容给补充上,希望能给朋友们帮上忙。当然如果想用手机和公司的OC通信,我们需…...
合肥 做网站的/百度新闻搜索
河津市文昕中学2019年招生政策问答2019年中考落下帷幕,自市教育局公布2019年中招报考新政策后,引起了家长和考生的强烈反响,不断有家长通过多渠道进行咨询,为此,我校就家长朋友们特别关心的几个问题作以下解答…...
汕头做网站公司/软文营销推广
RS-232C接口定义(DB9) 引脚 定义 符号 1 载波检测 DCD(Data Carrier Detect) 2 接收数据 RXD(Received Data) 3 发送数据 TXD(Transmit Data) 4 数据终端准备好 DTR(Data Terminal Ready&#x…...
旅游公司网站开发与实现/青岛招聘seo
作者:JOE,原文链接,原文日期:2016-05-01译者:ckitakishi;校对:mmoaay;定稿:CMB当前,有许多人正在努力将 Swift 3.0 引入到基于 ARM 的系统中。通过本文你将了…...
手机网站Com/最近新闻头条
C语言第8讲-结构体n课件第八讲-结构体与共用体;结构体与共用体;一、结 构 体;如: struct student { int num; char name[20]; char sex; int age; float score; char addr[30]; };;(2) 定义结构类型的同时定义结构变量;定义的一般形式:;(1) 类型与变量是不同的概念 …...
b2b是什么意思的/seo管理平台
JavaScript 框架 xmlplus 1.5.12 发布了。xmlplus 是一个设计非常独特 JavaScript 框架,用于快速开发前后端项目。 这个版本主要添加了一个全局接口 create。该函数是一个轻量的用于创建组件对象的函数,它只是简单地调用组件的函数项来返回所需的对象。 …...