普通视图

发现新文章,点击刷新页面。
今天 — 2024年5月29日首页

Common Knowledge 工作室 / THISS Studio

作者 Andreas Luco
2024年5月29日 19:00

Common Knowledge 工作室 / THISS Studio - 室内图, 餐厅, 桌子, 椅子Common Knowledge 工作室 / THISS Studio - 室内图, 起居室, 桌子, 隔断Common Knowledge 工作室 / THISS Studio - 室内图, 楼梯, 扶手Common Knowledge 工作室 / THISS Studio - 室内图, 视窗Common Knowledge 工作室 / THISS Studio - 更多图片+ 18

  • 建筑师: THISS Studio

  • 该建筑项目的领域 面积:  145
  • 该建筑项目的竣工年份 项目年份:  2023
  • 摄影师:Henry Woide

  • 该项目中使用产品的品牌

    厂家:  Dulux, EcoCork board supplied by Ty-Mawr Lime , King Upholstery, THISS Studio X Mitre and Mondays in Valchromat , THISS Studio X Mitre and Mondays/ Philips Hue

  • 设计团队: THISS Studio, Mitre and Mondays, Noatune

展开收起
Common Knowledge 工作室 / THISS Studio - 室内图, 餐厅, 桌子, 椅子
© Henry Woide

来自建筑师。THISS工作室巧妙地改造了位于 ShoreditchLeonard 街前仓库的上两层,为音乐管理集团 Common Knowledge 创建了一个新的办公室、共同工作空间和定制录音工作室。 为了挑战通常与音乐行业相关的严肃性和不可接近性,该项目旨在创造一个充满活力和灵活的社交中心,让人感觉像一个家外之家。

Common Knowledge 工作室 / THISS Studio - 室内图, 餐厅, 桌子, 视窗
© Henry Woide

THISS工作室倾向于将限制视为机会,对建筑和结构干预的限制引发了一种由定制家具,照明和货架定义的内部,创造了一个模块化和动态的空间,促进了音乐专业人员和录音艺术家之间的知识共享。 考虑到对空间的材料投资以及可持续性,THISS Studio邀请Mitre和Mondays作为合作者,开发了一系列可拆卸的家具,根据Common Knowledge的需求进行调整,以便他们将来搬到不同的空间。 THISS Studio和Mitre与Mondays紧密合作,共同开发和完善设计,并考虑到这些设计在商业使用中的寿命。

Common Knowledge 工作室 / THISS Studio - 室内图, 起居室, 桌子, 隔断
© Henry Woide
Common Knowledge 工作室 / THISS Studio - 室内图, 桌子, 隔断
© Henry Woide
Common Knowledge 工作室 / THISS Studio - 室内图, 起居室, 视窗
© Henry Woide

较大的建筑改造包括对第三和第四层的翻新和重组。 在可能的情况下进行恢复和改造,THISS Studio对整体设计采取了高度功能性但富有想象力的方法。 材料已经经过精心选择,以确保其声学特性,并以其原始形式融入其中,以接受共同工作环境的磨损。 THISS Studio与Mitre和Mondays紧密合作,开发原型,选择材料,开发技术细节,并将最终设计投入生产。 该项目在空间中建立了一种诚实感,采用了软木、铝和梧桐树的触感色调,这些梧桐树来自Euston附近一棵被砍伐的当地伦敦梧桐树。 每件作品都在Islington的Mitre和Mondays工作间当地制造而成。

Common Knowledge 工作室 / THISS Studio - 23 的图像 23
平面图

与周围的地方建筑风格相呼应,前仓库的广阔砖墙立面保持不变。 入口位于二楼,那里有一个开放的楼梯间,铺有深色木地板和厚重的红色valchromat扶手,并通往三楼的共同工作空间。 白色涂漆的横梁和椽子漂浮在贯穿斜屋顶长度的宽大玻璃下方,揭示了建筑的起源。 大量的自然光从上方进入,并通过两扇异常宽阔的窗户进入,突显了双层高的比例。 原本涂成白色的地板经过精心修复,重新涂上深色饰面,以增加承重感,同时也反射了房间周围的光线。

Common Knowledge 工作室 / THISS Studio - 室内图, 起居室, 沙发, 视窗
© Henry Woide
Common Knowledge 工作室 / THISS Studio - 室内图
© Henry Woide

就像一个连续的木工制品,红色valchromat继续环绕在楼梯间的顶部,在其外围形成了长椅座位和货架,架子用有机玻璃红色涂漆钢,用于存储书籍和黑胶唱片。 一个烤过的软木桌与匹配的凳子座椅增添了温暖,舒适和独特的触感。 设计为主要的共同工作桌空间,该桌由两个独立的半部分组成,可用于各种配置。 由非织造材料制成的定制帆作为抬高的中心装饰,悬挂于固定在公共软木桌子上方的两个天花板托梁之间的灰绿色钢框架上。 在经过认真的原型设计之后,Mitre和Mondays选择了一种非编织基膜材料以获得其柔性。 拉力索利用重力保持风帆处于完美的曲率状态,框架内的LED灯照亮了纸张的自然纹理,并产生温暖的家庭灯光。

Common Knowledge 工作室 / THISS Studio - 室内图, 楼梯, 扶手
© Henry Woide
Common Knowledge 工作室 / THISS Studio - 17 的图像 23
© Henry Woide

定制的、独立的铝制长凳座椅和红色软垫坐垫与整个办公室的红色valchromat细木工相呼应,以及内置的铝制办公桌,它们横跨整个共同工作空间的一侧。在每个桌面空间的框架中,涂有鼠尾草绿色的钢材在未经处理的平面细木工之间运行,这些细木工来自Fallen和fell,创建了记录展示架。 有意识选择的铝材料由于其轻质特性以及其可回收性和柔和的光泽而被选中。 为了增加连续性,软木板覆盖了墙壁的底部以吸收声音。 毗邻的厨房和浴室经过最小化的翻新和重新配置,以实现更好的流通。

Common Knowledge 工作室 / THISS Studio - 室内图, 视窗, 椅子, 桌子
© Henry Woide
Common Knowledge 工作室 / THISS Studio - 室内图, 桌子, 椅子
© Henry Woide

在中央楼梯的对面,现有的螺旋楼梯被改造成铝板和同样的鼠尾草绿色,以创造一种视觉上的连续性。 它上升到第四层的一个舒适的休息室,那里红色valchromat木工制品继续形成开放式存储和长椅,同时巧妙地隐藏了一个为毗邻的录音工作室提供通风的空气处理单元。裸露的砖块沿着两个房间之间的上部墙壁流动,以保留家庭生活感。 三面录音室配备了双层隔热层,并提供了跨多个立面的视野,使艺术家和制作人感觉好像在他们的办公室或卧室一样。

Common Knowledge 工作室 / THISS Studio - 18 的图像 23
© Henry Woide
Common Knowledge 工作室 / THISS Studio - 19 的图像 23
© Henry Woide

录音工作室是与Noatune合作设计的,通过绝缘地板和内衬墙将空间与主办公室隔离开。墙壁采用一系列织物面板,低音陷阱和valchromat扩散器,以创造适合创作歌曲的声学环境。 底座的软木板背后是羊毛隔音,用于声学扩散。 黑色松木制品与内部的圆形窗户相邻,俯瞰定制的照明风帆和下方的共同工作空间。 THISS工作室的办公室、共同工作空间和Common Knowledge定制录音室可被定义为诚实的材料性和固有的功能性。 THISS工作室挑战了工作场所设计的传统,为音乐专业人员创造了一个友好和家庭般的环境,供他们工作,交流,分享和激发灵感。

Common Knowledge 工作室 / THISS Studio - 室内图, 视窗
© Henry Woide
查看全部显示较少
点击以打开地图
地址仅作为参考。可显示城市/国家,但不提供精确地址。

引用: "Common Knowledge 工作室 / THISS Studio" [Common Knowledge Studio / THISS Studio] 29 5月 2024. ArchDaily. Accesed . <https://www.archdaily.cn/cn/1017055/common-knowledge-gong-zuo-shi-thiss-studio>;

Cycle Cycle 巡游亭 / F.O.G.建筑事务所

作者 Valeria Silva
2024年5月29日 17:00

Cycle Cycle 巡游亭 / F.O.G.建筑事务所 - 建筑图, 表皮Cycle Cycle 巡游亭 / F.O.G.建筑事务所 - 室内图Cycle Cycle 巡游亭 / F.O.G.建筑事务所 - 4 的图像 15Cycle Cycle 巡游亭 / F.O.G.建筑事务所 - 建筑图, 椅子Cycle Cycle 巡游亭 / F.O.G.建筑事务所 - 更多图片+ 10

  • 设计团队: 雷荣华、熊爱杰、侯绍凯、庄少凯、张智睿、刘嘉锐、詹迪、郑宇

展开收起
Cycle Cycle 巡游亭 / F.O.G.建筑事务所 - 建筑图
© INSPACE

来自建筑师。Cycle Cycle巡游亭是一个可移动的面包咖啡快闪店。对于“土地和食物”,我们与品牌方不谋而合:土地和食物的联系、建筑和人的联系,其实是同一叙述的“表”与“里”。我们通过对“风土”和“人情”的思考,试图用建筑的方式,找回当今社会中人与土地、人与人的连接。

Cycle Cycle 巡游亭 / F.O.G.建筑事务所 - 13 的图像 15
© INSPACE

Cycle Cycle 巡游亭 / F.O.G.建筑事务所 - 4 的图像 15
© INSPACE

小车的整体形象来源于谷仓,演变成了一个木框架结构,顶部支撑着防雨棚,侧面设有遮光板,让人联想到田地里供农民休憩的小草棚。立面多是用布袋堆叠而成,砖块的形状和粮食袋子的质感糅合在一起,产生一种坚固而平易近人的视觉效果。“布袋墙”上的细长开口位置偏低,使人们交流时有种从谷仓里探出脑袋的感觉。这些开口将内部活动有选择性地示人,让小车有了“台前幕后”之分。同时立面上错落的开口将自然光引入室内,透视关系和元素的堆叠削弱了建筑的尺度感。将遮光板支起、布帘散开,就能圈画出一个半私密空间。

Cycle Cycle 巡游亭 / F.O.G.建筑事务所 - 6 的图像 15
© INSPACE

Cycle Cycle 巡游亭 / F.O.G.建筑事务所 - 15 的图像 15
剖面图
Cycle Cycle 巡游亭 / F.O.G.建筑事务所 - 建筑图, 椅子
© INSPACE

我们在充分利用构造本身的基础上融入了一些“低技法”设计,引导人们自然随性地去跟小车互动,人的参与使其“亭”的特质更为突出了。比如小车的底盘是一圈座椅,布袋成了“靠垫”,梯形立柱充当“扶手”,且保证了用户的个人空间。座椅也参考了农村常见的矮板凳,这种特殊的尺度尽管细微,也有望让人们在互动中体会设计的意向。

Cycle Cycle 巡游亭 / F.O.G.建筑事务所 - 建筑图, 表皮
© F.O.G.建筑事务所
Cycle Cycle 巡游亭 / F.O.G.建筑事务所 - 建筑图, 视窗, 表皮
© INSPACE

小车为了满足不定期更换场地,它的体量和设计意向都更加强调公共性和向外延展的可能,如何与城市景观有机结合,甚至滋生出新的城市氛围。在现场安装时很多环节是排斥量化标准的,设计师和工人一起摸索答案,有一种即兴发挥的临时感。最能反映建筑本质的并非那些被抛光过的细节,而是雨棚上的凉席、质地粗糙的布料等等状态原始且不太可控的材料,它们始终保持随机性,更能在自然环境中发酵出野生的美感。

Cycle Cycle 巡游亭 / F.O.G.建筑事务所 - 建筑图, 表皮
© INSPACE
查看全部显示较少
点击以打开地图
地址仅作为参考。可显示城市/国家,但不提供精确地址。

引用: "Cycle Cycle 巡游亭 / F.O.G.建筑事务所" [Cycle Cycle mobile bakehouse / F.O.G. Architecture] 29 5月 2024. ArchDaily. Accesed . <https://www.archdaily.cn/cn/1017090/cycle-cycle-xun-you-ting-fogjian-zhu-shi-wu-suo>;

# 羞耻心计划

作者 ONO
2024年5月29日 11:00

因为那天不小心翻到了初中-大学时期的记事本,突然萌生了一个折磨自己的写作计划——# 羞耻心计划。

学生时代总是会留下很多现在看起来极度羞耻的记录,“如果你在临死前,可以朝任何一个人开上一枪,你会把枪口举向谁?”就是其中一个,结合了痛经文学、文艺青年的言辞,让人到中年的我难以启口。

记事本的内容很杂,封面的励志格言、课表、只有制定没有遵循过得寒暑假计划、灵感记录、乱涂乱画、学习笔记(反正就是跟高考无关的学习笔记)、朋友的电话号码、跟朋友的书信来往、毕业前我为几个好友自制的同学录、誊抄的歌词、仓央嘉措的诗、摘抄的文学作品、小说的构想设定……最牛逼的是,我找到了《城市,一座立体的权力花园 II》最初的雏形笔记。

p.s. 在左上角,我那个时候就对“莫比乌斯”有了兴趣,果然这个博客的名字由来是有历史渊源的。

初中的言辞受限于认知,所以总能总结出的都是非常流于表面的疼痛文辞。也是因为整理才意识到,从那个时候开始,我竟然就已经如此地喜欢“死亡”、“新生”、“毁灭”和“重建”这些概念。


另一个视角,是记事本里其实记录了非常多的“故事”,这些故事都是我观察来的。而立之年后的认知开始有了知识框架后,这些“故事”都能找到对应的分类——比如记录一对情侣的吵架,吵架的内容并不是关键,而是女性要得是“情绪价值”,男性努力在提供“解决办法”。

把这些故事再重新分类,或许可以看到另一个新的视角,也算是对人生经验的一种总结吧。


然而,这个计划被称之为“羞耻心计划”,不仅仅是因为看到这些历史记录有一种莫名的羞耻感,更重要的是,羞耻感是最接近死亡的感觉。我“有幸”经历过肉体的濒死,它让我的感知和认知都有了一种重生的感觉,堪悟了很多以前困住自己的坚持。既然如此,精神的濒死感,或许也能激发更多的灵感。

很多年前,我也秉持一种“观念”——当一个人开始回顾自己过去的时候,就说明他已经没有了未来的希冀。就像是一个老男人,在酒桌上吹嘘自己曾经同时睡过三个小姐一样——他是不是真的夸大其词,一戳就破,但是如果他真的睡过三个小姐呢?我还真愿意听这样的人讲他的人生经历,而不是在酒桌上为中美日俄关系指明未来方向。

回顾过去的前提,是他得有回顾的历史——而不是翻来覆去地讲述他睡过三个小姐。

这个逻辑用在我这里也同样适用——“你回顾你的人生有什么用呢?”

“那你先坚持一整年每天写一篇博客再来批判吧!”

话不中听,且理还血淋淋的。

至于# 羞耻心计划 的中心思想到底是什么,我也没有想到,倒是记事本的封底誊抄了晏殊的《浣溪沙》,在里面还特别着重了一句,那就是这个计划的主题——不如怜取眼前人。我在完成# 羞耻心计划 之后,决定把这两个记事本给毁掉。

Exploring the Impact of Top-Level cv-qualifiers on type-deduction -- Andreas Fertig

作者 Blog Staff
2024年5月29日 06:31

me.pngIn today's post, I will continue where I left off with last month's post Understanding the role of cv-qualifiers in function parameters. This time, I will focus on type deduction.

Exploring the Impact of Top-Level cv-qualifiers on type-deduction

by Andreas Fertig

From the article:

typededuction-fertig.png

分布式数据库入门:以国产数据库 TDSQL 为例

作者 阮一峰
2024年5月29日 09:03

一、简介

今天,跟大家分享一些企业级的互联网技术。

我要介绍的就是分布式数据库(distributed database)。我尽量用通俗的语言,说清楚它的概念、产品和用法,文末还会提供学习资料下载。

分布式数据库堪称最重要的数据库,几乎所有你知道的大型互联网服务,都运行在它之上。

平时,我们自己开发,接触的都是单机数据库(又称集中式数据库),就是数据库只运行在一台服务器上。

(图片说明:左侧的单个数据库服务器,支撑着整个应用。)

分布式数据库指的是,数据库系统分布在多台服务器。

(图片说明:单个数据库分布在多台服务器上,共同支撑应用。)

在宏观层面,金融、电信、航空、物流、电商等国民经济的重要产业,都离不开分布式数据库。

如果没有它,我们很难想象生活会变成什么样,比如12306那样的购票网站,就没法提供服务了。

在个人层面,当你从初级开发者成长为大型项目的架构师,就多多少少会遇到分布式数据库。

设计架构时,除非只用一台服务器,否则就免不了要考虑,数据在多台服务器之间如何拆分和保存。

总之,产品做大以后,分布式数据库是避不开的。对于个人来说,这也意味着事业和能力的进步。

二、分布式数据库的优点

分布式数据库为什么那么重要?因为它有一些单机数据库无法比拟的优点。

(1)更安全。分布式数据库包含多个节点,不管是放在同一个机房,还是不同机房,都要比单机数据库安全得多。

(2)高可用。如果单个数据库节点故障下线,其他节点还可以照常工作,不会单点失败。

(3)性能更好。对于大数据、大计算量的任务,分布式数据库可以并行处理,大大缩短处理时间。

(4)体验更好。当数据库分布在多个机房,可以为用户分配就近的数据库节点,提供更好的响应速度。

三、分布式数据库的难点

虽然有上面这些优点,但是分布式数据库的使用并不普及,小公司一般不用它,这是为什么?

主要原因是,分布式数据库有两大问题,阻碍了它的普及:成本高和复杂性。

分布式数据库属于"异地多活",提供了额外的冗余性,来保障数据安全,成本高自不必多言。

它的复杂性主要体现在下面几点。

(1)一致性问题。如何保证不同节点的数据一致?如果节点的数据不一致怎么办?

(2)通信问题。怎样保证节点之间的通信可靠?如果通信延迟或失败怎么办?

(3)分区问题。如果拆分大型数据表,数据储存在不同的节点,那么拆分策略、节点间的数据迁移可能会非常复杂。

(4)优化问题。如果来自多个节点的数据需要组合,查询就必须优化以提高性能。

四、CAP 定理

大家可能知道,有一条著名的 CAP 定理,说的就是分布式系统(包括分布式数据库)无法克服的局限性。

分布式系统有三大目标----数据一致(Consistency)、高可用(Availability)、数据分区(Partition tolerance)。

CAP 定理告诉我们,三大目标无法同时满足,最多只能同时做到两个。在数据分区的前提下,要么为了(强)一致性,舍弃高可用;要么为了高可用,舍弃(强)一致性。

因此,任何分布式数据库都做不到完美,只能是三大目标的某种取舍和均衡。

五、分布式数据库的产品

分布式数据库的历史非常悠久,市场上至少有上百种产品,有开源的,也有闭源的。

几乎所有的分布式数据库,既可以单机使用(即作为单机数据库),也可以多机联合,分布式使用。因此,很多我们熟悉的单机数据库,其实也是分布式数据库。

开源的分布式数据库,比较有名的是 Postgres 和 MySQL(关系型数据库),以及 MongoDB 和 CockroachDB(非关系型数据库)。

商业数据库里面,最有名的就是 Oracle。它是分布式数据库事实上的标准,大企业一般都选择用它。

六、国产数据库 TDSQL

下面,我选择国产数据库 TDSQL 作为示例,介绍分布式数据库的功能和用法。

TDSQL 是腾讯的产品,属于国内领先的分布式数据库。腾讯的几乎所有关键业务,比如微信、QQ、腾讯音乐、腾讯游戏等等,都运行在它之上,经受了高强度、海量的实战考验。

外部很多大公司也在用它,比如小红书、拼多多、B 站、海尔、深圳地铁等等。

它完全按照金融级的标准打造,属于金融级数据库,注重安全、高可用、高并发,客户目前超过50万。在国内金融行业,它服务 TOP10 银行中的7家,已经助力30余家金融机构的核心系统改造。

TDSQL 是完全的国产数据库,特别强调 Oracle 的兼容,企业现有的 Oracle 数据库可以平滑迁移,它的成本要比 Oracle 低很多。如果国内企业有国产化和供应链安全的考虑,它是很好的替代品。

它的产品能力和自主研发,通过了国家认证(《中国信息安全测评中心的安全可靠测评结果公告(2023年第1号)》),对于国有企业的技术选型,这也是很重要的考虑之一。

最后,TDSQL 是腾讯云对外公开的一个服务,任何人都可以使用。只要在网页上点击几下,就开通了,非常容易上手。

七、分布式数据库的功能

我们通过 TDSQL,看看分布式数据库有哪些功能。

(1)强同步复制。分布式数据库往往采用主从式架构,一个集群有一个主节点(master)和若干个从节点(slave)。系统支持节点之间的强同步复制,以保证数据一致。

具体来说,写入数据时,主节点会等待从节点返回操作成功消息,然后才向用户返回结果,这样保证了主节点和从节点的数据完全一致。

(2)事务一致性。系统为每一笔事务提供全局唯一数字序列,每个节点都可以查询事务的执行情况,保证在分布式环境下的事务一致性。

(3)自动拆分。分布式数据库的大型数据表,往往需要进行拆分,储存在不同的节点。TDSQL 支持自动水平拆分(分表),将数据均匀写入到不同节点,查询时也自动聚合返回。

对于用户来说,分表是透明的,完全可以无视,业务端看到的就是一张逻辑完整的表,无需感知后端的分表细节。

(4)高度可扩展。当数据库性能或容量不足时,TDSQL 可以不停机扩展,只需在控制台点击,就可自动升级完成。系统内的数据迁移、数据均衡和路由切换,都是自动的。

(5)高度灵活性。用户可以在线变更表结构;遇到某些类型的故障,系统可以自动恢复;所有节点,不管是主节点还是从节点,都可进行读写。

(6)产品管控能力。TDSQL 对开发者友好,提供大量监控工具,实时监控和告警,每日推送详细的健康探查报告。

腾讯云有一个专门的云服务 DBbrain,利用机器学习、大数据、专家经验引擎等手段,为用户的数据库提供性能、安全、管理等功能。

比如,它会全方位诊断和优化 SQL,发现性能瓶颈,让 SQL、事务、业务流水全链路可观测,可视化展现死锁等异常,易于理解。

它很大程度上了替代了人工 DBA,将传统的人工运维变成智能化服务。

TDSQL 还有一个 AI 智能问答系统(下图)。它基于知识库与小模型训练,快速准确地响应用户查询,相当于一个智能客户,提供专业且个性化的解答。

八、TDSQL 的用法

下面,我来演示一下 TDSQL 的用法,很简单,在网页上开通后,你就可以使用分布式数据库了。

第一步,在 TDSQL 的官网上,进入产品控制台。

第二步,在控制台页面,选择数据库服务器所在的地域(跟你的云服务器应该是同一个地域),以及数据库引擎,然后点击"新建"按钮。

目前 TDSQL 有三种引擎:MySQL、自研的 TDStore 和 PostgreSQL。不管哪一种引擎,都具备一样的容灾能力和高可用,并且兼容 Oracle。

第三步,会跳出一个配置页面,让你选择数据库配置。不同的配置,价格不一样。

其中有一项,问你要不要开通"强同步"。

强同步可以确保主节点和从节点的数据一致性。如果你的应用不要求强一致,更在意快速返回结果,这里可以选择"异步"。

第四步,配置完成后,会进入付款环节,然后数据库就开通了,你的分布式数据库就已经在线了。

使用时,需要先连接数据库,分成内网连接和外网连接,这里可以参考文档。需要注意,如果开通外网连接,数据库就暴露在公网上,任何人都可以请求,必须注意安全风险。

连接数据库以后,就可以执行 SQL 语句了,到了这一步,就跟使用普通数据库没有任何区别。分布式数据库的 SQL 与单机数据库,基本是一样的

九、TDSQL 的最佳实践

分布式数据有一些最佳实践,下面举出三个(以 MySQL 引擎为例)。

(1)如何将数据导入分布式数据库

这分成两种情况。第一种情况是将现有的单机实例,导入到新建的分布式实例。操作步骤如下(详细命令见文档)。

  1. 导出单机数据库的表结构和数据,拿到两个 SQL 文件。
  2. 打开数据库的表结构文件,设置每个表的主键(primary key),以及分片依据的 shardkey。
  3. 将修改后的两个 SQL 文件,上传到云服务器,导入到分布式数据库。

第二种情况是将现有的一个分布式实例,导入到另一个分布式实例。操作步骤与上面一样,只是少了第二步,不需要指定主键和 shardkey,因为原来就有了。(详细命令见文档)。

(2)如何分片

分片(sharding)是分布式数据库的核心问题之一:到底要架设多少个数据分区?数据在多个分区如何分布?

分片数量取决于,整个数据库预估的最大并发,以及每个分片能够处理的请求数量,可以用下面的公式计算。

读写并发性能 = ∑(分片性能 * 分片数量)

单个分片的性能,主要与实例的 CPU / 内存数量相关。单个分片规格越高、分片数量越多,数据库系统的处理能力越强。

除了性能,分片还要考虑容量问题。一般来说,单个分片至少存储5000万行数据。

(3)如何配置硬件

分布式数据库的硬件,下面给出三个推荐的配置。

A. 测试功能。

这种情况不要求性能,只用来验证系统,建议配置2个节点,每个节点 2GB 内存 + 25GB 硬盘。

B. 业务发展初期。

这种情况数据规模较小,增长快,建议配置2个节点,每个节点 16GB 内存 + 200GB 硬盘。

C. 业务发展稳定期。

这种情况根据业务实际情况配置,可以配置4个节点,每个节点硬件为:(当前业务峰值 * 增长率) / 4。

十、总结

总的来说,当代的分布式数据库产品,将自身的大量复杂性,都隐藏了起来,为用户提供一个易用的操作接口。

一般来说,不建议自己搭建分布式数据库,即使你有专门的数据库工程师和运维工程师,成本也会非常高。使用云服务商的产品,是更经济更省事的选择。

就拿 TDSQL 来说,它有两个版本:集群版和基础版。前者是多节点的,供企业在生产环境使用;后者是单节点的,费用较低,专门供个人使用,但功能是一样的,很适合个人开发者学习或者尝试分布式数据库。

(完)

福利内容

在这个 AI 时代,如何使用云服务,助力企业的数据管理?

下面是三个国内大厂的真实案例。

案例一:微信读书的"AI 问书"。这个功能让 AI 来回答读者提问,关于海量的书籍内容的各种问题。

案例二:海峡银行核心系统升级。省级银行如何使用 TDSQL,将核心系统升级为分布式数据库。

案例三:极光大数据平台的架构优化。极光(URORA)是国内领先的开发者服务提供商,数据量近百 PB,节点过千,文件4亿,应该如何优化架构?

它们来自腾讯云内部编写的资料 《AGI 时代首选的全栈式数据管理方案》 ,包括工具指南、用户案例分享等诸多内容。

现在可以免费下载,只需微信扫描下方二维码。如果你关注国内真实环境中的企业级开发,不妨看看。

文档信息

  • 版权声明:自由转载-非商用-非衍生-保持署名(创意共享3.0许可证
  • 发表日期: 2024年5月29日

losehu/uv-k5-firmware-custom

2024年5月29日 10:10

全功能泉盛UV-K5/K6固件 Quansheng UV-K5/K6 Firmware


Read this in other languages: English, 中文.

语言版本: English, 中文.

版本说明

  • 目前分为五个版本:LOSEHUxxxLOSEHUxxxKLOSEHUxxxHLOSEHUxxxELOSEHUxxxEK
  • LOSEHUxxx:中文固件,无需扩容,包含MDC1200、频谱、收音机
  • LOSEHUxxxK:中文固件,需要1Mib以上Eeprom,包含多普勒模式、MDC1200、频谱、收音机、中文信道名、自定义开机中文字符、开机图片
  • LOSEHUxxxH:中文固件,需要2Mib以上Eeprom,包含多普勒模式、中文输入法、频谱、收音机、中文信道名、自定义开机中文字符、开机图片
  • LOSEHUxxxE:英文固件,无需扩容,包含MDC1200、频谱、收音机、短信
  • LOSEHUxxxEK:英文固件,需要1Mib以上Eeprom,包含多普勒模式、MDC1200、频谱、收音机、自定义开机字符、开机图片

写频方式

关于多普勒卫星、开机图片文字的写频方式

请参考:K5Web

多功能的K5/6固件

该固件基于多个开源固件修改合并,拥有最多样性的功能

  • 更大容量的Eeprom芯片
  • 自动多普勒频移
  • 自定义开机图
  • SI4732支持(实现中。。)
  • 中/英文支持
  • 中文输入法
  • GB22312中文界面、信道
  • 频谱图
  • MDC1200信令、联系人
  • 短信
  • 信号强度指示器( S表 )
  • 一键扫频
  • 收音机
  • AM 修复
  • SSB 解调

操作说明(必读!!)

按键 功能
🐤 主界面下
单按上/下 调整频率(步长为菜单1项步进频率
单按数字 在频率模式下快捷输入频率
单按* 输入要发送的DTMF(A、B、C、D、*、#对应M、上、下、*、F键侧键1退格,按PPT键发送)
长按F 锁定键盘
长按M 切换调制模式
长按* 信道模式下是搜索列表,多次长按可切换(列表1/2/全部),频率模式下,从当前频率开始搜索
长按0/F+0 打开/关闭收音机
长按1/F+1 在信道模式下将当前信道复制到另一个VFO
长按2/F+2 切换A/B通道
长按3/F+3 切换频率/信道
长按4/F+4 一键对频
长按5 信道模式下切换搜索列表
长按5 频率模式下设置搜索频率范围(从通道A到通道B频率),按*键开始搜索
F+5 频谱
长按6/F+6 切换发射功率
长按7/F+7 声控发射开关
长按8/F+8 一键倒频
长按9/F+9 一键即呼
F+M 打开短信
F+UP 按键音开关
F+Down 自动多普勒
F+EXIT 菜单上下颠倒
F+* 扫描(数字/模拟)亚音
短按侧键1 监听
长按侧键1 DTMF解码开关
短按侧键2 设置宽窄带
长按侧键2 手电筒
宽窄带、DTMF解码、切换FM/AM/USB 集成至自定义的 侧键与M

Eeprom分布说明

Eeprom地址 描述
😭 通用 版本号:LOSEHUxxx
0X01D00~0x02000 基本不变
0X01D00 ~ 0X01E00
0X1F90 ~ 0X01FF0
MDC1200-22个MDC联系人
每个联系人占用16B,前2B为MDC ID,后14B为联系人名
0X01FFF MDC1200-MDC联系人数量
0x01FFD~0x01FFE MDC1200-MDC ID
0x01FF8~0x01FFC 侧键功能
0x01FFD~0x01FFE MDC1200-MDC ID
😱 扩容版(K、H) 版本号:LOSEHUxxxK、LOSEHUxxxH
0x02000~0x02012 开机字符1
0x02012~0x02024 开机字符2
0x02024~0x02025 开机字符1、2的长度
0x02080~0x02480 开机画面,长度128(宽)*64/8=1024=0x400
0x01FFD~0x01FFE MDC1200-MDC ID
0x02480~0x0255C gFontBigDigits,长度11*20=220=0XDC
0x0255C~0x0267C gFont3x5,长度96*3=288=0X120
0x0267C~0x028B0 gFontSmall,长度96*6=564=0X234
0x028B0~0x02B96 菜单编码,长度53*14=742=0X2E6
0x02BA0~0x02BA9 多普勒-卫星名称,首字符在前,最多9个英文,最后一个为'\0'
0x02BAA~0x02BAF 多普勒-开始过境时间的年份十位个位、月、日、时、分、秒
0x02BB0~0x2BB5 多普勒-离境时间的年份十位个位、月、日、时、分、秒
0x02BB6~0x02BB7 多普勒-总过境时间(秒),低位在前,高位在后
0x02BB8~0x02BB9 多普勒-手台的发射亚音,低位在前,高位在后
0x02BBA~0x02BBB 多普勒-手台的接收亚音,低位在前,高位在后
0x02C00~0x02C64 多普勒-CTCSS_Options,长度50*2=100=0x64
0x02C64~0x02D34 多普勒-DCS_Options,长度104*2=208=0xD0
0x02BBC~0X02BBF 多普勒-开始过境时间与2000年1月1日UNIX时间戳的差,低位在前,高位在后
0X02BC0~0X02BC5 多普勒-当前时间的年份十位个位、月、日、时、分、秒
0x02E00~0x1E1E6 GB2312中文字库,共67631112/8=111590=0x1B3E6
0x1E200~0x20000(MAX) 多普勒-第2*n(偶数)秒卫星数据,每秒8B,包括上下行频率/10,低位在前,高位在后
😰 2Mib扩容版(H) 版本号:LOSEHUxxxH
0x20000~0x26B00 中文输入法-拼音索引、对应字数、字的起始地址
0x26B00~0x2A330 中文输入法-拼音汉字表
0x3C228~0x40000 SI4732-patch,长度为0x3DD8,用于SI4732的固件升级

多普勒Eeprom分布说明

示例

用户功能自定义

你可以通过启用/禁用各种编译选项来定制固件

编译选项 描述
🧰 泉盛基本功能 Quansheng Basic Functions
ENABLE_UART 串口,没有这个,你就不能通过PC配置无线电!
ENABLE_AIRCOPY AirCopy无线复制
ENABLE_FMRADIO 收音机功能
ENABLE_NOAA NOAA功能 (只有在美国有用)
ENABLE_VOICE 语音播报
ENABLE_VOX VOX声控发射
ENABLE_ALARM TX 警报
ENABLE_PWRON_PASSWORD 开机密码
ENABLE_DTMF_CALLING DTMF拨号功能,呼叫发起,呼叫接收,群组通话,联系人列表等
ENABLE_FLASHLIGHT 启用顶部手电筒LED灯(开启,闪烁,SOS)
自定义模组
ENABLE_BIG_FREQ 大号字体的频率显示(类似官方泉盛固件)
ENABLE_KEEP_MEM_NAME 在重新保存内存频道时保持频道名称
ENABLE_WIDE_RX 全频18MHz至1300MHz接收(尽管前端/功率放大器未设计用于整个范围)
ENABLE_TX_WHEN_AM 当RX设置为AM时允许TX(始终为FM)
ENABLE_F_CAL_MENU 启用收音机的隐藏频率校准菜单
ENABLE_CTCSS_TAIL_PHASE_SHIFT 使用标准CTCSS尾部相移,而不是QS独有的55Hz音调方法
ENABLE_BOOT_BEEPS 在启动时为用户提供音频反馈,指示音量旋钮的位置
ENABLE_SHOW_CHARGE_LEVEL 在收音机充电时显示电池充电水平
ENABLE_REVERSE_BAT_SYMBOL 在状态栏上镜像电池符号(正极在右侧)
ENABLE_NO_CODE_SCAN_TIMEOUT 禁用32秒CTCSS/DCS扫描超时(按退出按钮而不是等待超时结束扫描
ENABLE_AM_FIX 在AM模式下动态调整前端增益,以帮助防止AM解调器饱和,暂时忽略屏幕上的RSSI级别
ENABLE_SQUELCH_MORE_SENSITIVE 将静噪电平稍微调敏感一些
ENABLE_FASTER_CHANNEL_SCAN 增加频道扫描速度,但静噪调敏度也增加了
ENABLE_RSSI_BAR 启用以dBm/Sn为单位的RSSI条形图水平,取代小天线符号
ENABLE_AUDIO_BAR 发送时显示音频条级别
ENABLE_COPY_CHAN_TO_VFO 将当前频道设置复制到频率模式。在频道模式下长按 1 BAND
ENABLE_SPECTRUM fagci 频谱分析仪,F + 5 NOAA激活
ENABLE_REDUCE_LOW_MID_TX_POWER 使中等和低功率设置更低
ENABLE_BYP_RAW_DEMODULATORS 额外的BYP(旁路?)和RAW解调选项,被证明并不十分有用,但如果你想实验的话,它是存在的
ENABLE_SCAN_RANGES 频率扫描的扫描范围模式
ENABLE_BLOCK Eeprom上锁
ENABLE_WARNING BEEP提示音
ENABLE_CUSTOM_SIDEFUNCTIONS 自定义侧键功能
ENABLE_SIDEFUNCTIONS_SEND 自定义侧键功能(侧键发射功能)
ENABLE_AUDIO_BAR_DEFAULT 默认语音条样式
📡 自动多普勒 Automatic Doppler
ENABLE_DOPPLER 自动多普勒功能
📧 短信 SMS
ENABLE_MESSENGER 发送和接收短文本消息(按键 = F + MENU
ENABLE_MESSENGER_DELIVERY_NOTIFICATION 如果收到消息,则向发送方发送通知
ENABLE_MESSENGER_NOTIFICATION 在收到消息时播放声音
📱 MDC1200 MDC1200
ENABLE_MDC1200 MDC1200发送功能
ENABLE_MDC1200_SHOW_OP_ARG MDC显示首尾音参数
ENABLE_MDC1200_SIDE_BEEP MDC侧音
ENABLE_MDC1200_CONTACT MDC联系人
🎛️ DOCK DOCK
ENABLE_DOCK 允许通过电脑控制手台,无屏幕显示!
🚫 调试
ENABLE_AM_FIX_SHOW_DATA 显示AM修复的调试数据
ENABLE_AGC_SHOW_DATA 显示ACG参数
ENABLE_UART_RW_BK_REGS 添加了两个额外的命令,允许读取和写入BK4819寄存器
⚠️ 编译选项
ENABLE_CLANG 实验性质,使用clang而不是gcc构建(如果启用此选项,LTO将被禁用)
ENABLE_SWD 使用CPU的SWD端口,调试/编程时需要
ENABLE_OVERLAY CPU FLASH相关内容,不需要
ENABLE_LTO 减小编译固件的大小,但可能会破坏EEPROM读取(启用后OVERLAY将被禁用)

打赏

如果这个项目对您有帮助,可以考虑赞助来支持开发工作。

这是:打赏名单 非常感谢各位的支持!!!

打赏码:

打赏码

免责声明:

  • 本固件仅供技术交流和个人学习使用。任何个人或组织在使用本固件时必须遵守中华人民共和国相关法律法规及无线电管理条例
  • 作者对于他人使用本固件所产生的任何违法行为概不负责,包括但不限于未经授权擅自修改、使用本固件进行非法活动等行为。
  • 如因使用本固件造成的损失,作者不承担任何法律责任
  • 使用者在下载、安装和使用本固件时,默认已经阅读、理解并同意本免责声明的所有内容。如有异议,请立即停止使用本固件
  • 作者保留在法律允许范围内对本免责声明进行解释和修改的权利。**任何未经授权的固件修改、传播所造成的违法行为,一概与作者无关 **。

yhirose/cpp-httplib

2024年5月29日 10:10

A C++ header-only HTTP/HTTPS server and client library


cpp-httplib

A C++11 single-file header-only cross platform HTTP/HTTPS library.

It's extremely easy to setup. Just include the httplib.h file in your code!

[!IMPORTANT] This library uses 'blocking' socket I/O. If you are looking for a library with 'non-blocking' socket I/O, this is not the one that you want.

Simple examples

Server (Multi-threaded)

#define CPPHTTPLIB_OPENSSL_SUPPORT
#include "path/to/httplib.h"

// HTTP
httplib::Server svr;

// HTTPS
httplib::SSLServer svr;

svr.Get("/hi", [](const httplib::Request &, httplib::Response &res) {
  res.set_content("Hello World!", "text/plain");
});

svr.listen("0.0.0.0", 8080);

Client

#define CPPHTTPLIB_OPENSSL_SUPPORT
#include "path/to/httplib.h"

// HTTP
httplib::Client cli("http://cpp-httplib-server.yhirose.repl.co");

// HTTPS
httplib::Client cli("https://cpp-httplib-server.yhirose.repl.co");

auto res = cli.Get("/hi");
res->status;
res->body;

SSL Support

SSL support is available with CPPHTTPLIB_OPENSSL_SUPPORT. libssl and libcrypto should be linked.

[!NOTE] cpp-httplib currently supports only version 3.0 or later. Please see this page to get more information.

[!TIP] For macOS: cpp-httplib now can use system certs with CPPHTTPLIB_USE_CERTS_FROM_MACOSX_KEYCHAIN. CoreFoundation and Security should be linked with -framework.

#define CPPHTTPLIB_OPENSSL_SUPPORT
#include "path/to/httplib.h"

// Server
httplib::SSLServer svr("./cert.pem", "./key.pem");

// Client
httplib::Client cli("https://localhost:1234"); // scheme + host
httplib::SSLClient cli("localhost:1234"); // host
httplib::SSLClient cli("localhost", 1234); // host, port

// Use your CA bundle
cli.set_ca_cert_path("./ca-bundle.crt");

// Disable cert verification
cli.enable_server_certificate_verification(false);

[!NOTE] When using SSL, it seems impossible to avoid SIGPIPE in all cases, since on some operating systems, SIGPIPE can only be suppressed on a per-message basis, but there is no way to make the OpenSSL library do so for its internal communications. If your program needs to avoid being terminated on SIGPIPE, the only fully general way might be to set up a signal handler for SIGPIPE to handle or ignore it yourself.

Server

#include <httplib.h>

int main(void)
{
  using namespace httplib;

  Server svr;

  svr.Get("/hi", [](const Request& req, Response& res) {
    res.set_content("Hello World!", "text/plain");
  });

  // Match the request path against a regular expression
  // and extract its captures
  svr.Get(R"(/numbers/(\d+))", [&](const Request& req, Response& res) {
    auto numbers = req.matches[1];
    res.set_content(numbers, "text/plain");
  });

  // Capture the second segment of the request path as "id" path param
  svr.Get("/users/:id", [&](const Request& req, Response& res) {
    auto user_id = req.path_params.at("id");
    res.set_content(user_id, "text/plain");
  });

  // Extract values from HTTP headers and URL query params
  svr.Get("/body-header-param", [](const Request& req, Response& res) {
    if (req.has_header("Content-Length")) {
      auto val = req.get_header_value("Content-Length");
    }
    if (req.has_param("key")) {
      auto val = req.get_param_value("key");
    }
    res.set_content(req.body, "text/plain");
  });

  svr.Get("/stop", [&](const Request& req, Response& res) {
    svr.stop();
  });

  svr.listen("localhost", 1234);
}

Post, Put, Delete and Options methods are also supported.

Bind a socket to multiple interfaces and any available port

int port = svr.bind_to_any_port("0.0.0.0");
svr.listen_after_bind();

Static File Server

// Mount / to ./www directory
auto ret = svr.set_mount_point("/", "./www");
if (!ret) {
  // The specified base directory doesn't exist...
}

// Mount /public to ./www directory
ret = svr.set_mount_point("/public", "./www");

// Mount /public to ./www1 and ./www2 directories
ret = svr.set_mount_point("/public", "./www1"); // 1st order to search
ret = svr.set_mount_point("/public", "./www2"); // 2nd order to search

// Remove mount /
ret = svr.remove_mount_point("/");

// Remove mount /public
ret = svr.remove_mount_point("/public");
// User defined file extension and MIME type mappings
svr.set_file_extension_and_mimetype_mapping("cc", "text/x-c");
svr.set_file_extension_and_mimetype_mapping("cpp", "text/x-c");
svr.set_file_extension_and_mimetype_mapping("hh", "text/x-h");

The followings are built-in mappings:

Extension MIME Type Extension MIME Type
css text/css mpga audio/mpeg
csv text/csv weba audio/webm
txt text/plain wav audio/wave
vtt text/vtt otf font/otf
html, htm text/html ttf font/ttf
apng image/apng woff font/woff
avif image/avif woff2 font/woff2
bmp image/bmp 7z application/x-7z-compressed
gif image/gif atom application/atom+xml
png image/png pdf application/pdf
svg image/svg+xml mjs, js application/javascript
webp image/webp json application/json
ico image/x-icon rss application/rss+xml
tif image/tiff tar application/x-tar
tiff image/tiff xhtml, xht application/xhtml+xml
jpeg, jpg image/jpeg xslt application/xslt+xml
mp4 video/mp4 xml application/xml
mpeg video/mpeg gz application/gzip
webm video/webm zip application/zip
mp3 audio/mp3 wasm application/wasm

[!WARNING] These static file server methods are not thread-safe.

File request handler

// The handler is called right before the response is sent to a client
svr.set_file_request_handler([](const Request &req, Response &res) {
  ...
});

Logging

svr.set_logger([](const auto& req, const auto& res) {
  your_logger(req, res);
});

Error handler

svr.set_error_handler([](const auto& req, auto& res) {
  auto fmt = "<p>Error Status: <span style='color:red;'>%d</span></p>";
  char buf[BUFSIZ];
  snprintf(buf, sizeof(buf), fmt, res.status);
  res.set_content(buf, "text/html");
});

Exception handler

The exception handler gets called if a user routing handler throws an error.

svr.set_exception_handler([](const auto& req, auto& res, std::exception_ptr ep) {
  auto fmt = "<h1>Error 500</h1><p>%s</p>";
  char buf[BUFSIZ];
  try {
    std::rethrow_exception(ep);
  } catch (std::exception &e) {
    snprintf(buf, sizeof(buf), fmt, e.what());
  } catch (...) { // See the following NOTE
    snprintf(buf, sizeof(buf), fmt, "Unknown Exception");
  }
  res.set_content(buf, "text/html");
  res.status = StatusCode::InternalServerError_500;
});

[!CAUTION] if you don't provide the catch (...) block for a rethrown exception pointer, an uncaught exception will end up causing the server crash. Be careful!

Pre routing handler

svr.set_pre_routing_handler([](const auto& req, auto& res) {
  if (req.path == "/hello") {
    res.set_content("world", "text/html");
    return Server::HandlerResponse::Handled;
  }
  return Server::HandlerResponse::Unhandled;
});

Post routing handler

svr.set_post_routing_handler([](const auto& req, auto& res) {
  res.set_header("ADDITIONAL_HEADER", "value");
});

'multipart/form-data' POST data

svr.Post("/multipart", [&](const auto& req, auto& res) {
  auto size = req.files.size();
  auto ret = req.has_file("name1");
  const auto& file = req.get_file_value("name1");
  // file.filename;
  // file.content_type;
  // file.content;
});

Receive content with a content receiver

svr.Post("/content_receiver",
  [&](const Request &req, Response &res, const ContentReader &content_reader) {
    if (req.is_multipart_form_data()) {
      // NOTE: `content_reader` is blocking until every form data field is read
      MultipartFormDataItems files;
      content_reader(
        [&](const MultipartFormData &file) {
          files.push_back(file);
          return true;
        },
        [&](const char *data, size_t data_length) {
          files.back().content.append(data, data_length);
          return true;
        });
    } else {
      std::string body;
      content_reader([&](const char *data, size_t data_length) {
        body.append(data, data_length);
        return true;
      });
    }
  });

Send content with the content provider

const size_t DATA_CHUNK_SIZE = 4;

svr.Get("/stream", [&](const Request &req, Response &res) {
  auto data = new std::string("abcdefg");

  res.set_content_provider(
    data->size(), // Content length
    "text/plain", // Content type
    [&, data](size_t offset, size_t length, DataSink &sink) {
      const auto &d = *data;
      sink.write(&d[offset], std::min(length, DATA_CHUNK_SIZE));
      return true; // return 'false' if you want to cancel the process.
    },
    [data](bool success) { delete data; });
});

Without content length:

svr.Get("/stream", [&](const Request &req, Response &res) {
  res.set_content_provider(
    "text/plain", // Content type
    [&](size_t offset, DataSink &sink) {
      if (/* there is still data */) {
        std::vector<char> data;
        // prepare data...
        sink.write(data.data(), data.size());
      } else {
        sink.done(); // No more data
      }
      return true; // return 'false' if you want to cancel the process.
    });
});

Chunked transfer encoding

svr.Get("/chunked", [&](const Request& req, Response& res) {
  res.set_chunked_content_provider(
    "text/plain",
    [](size_t offset, DataSink &sink) {
      sink.write("123", 3);
      sink.write("345", 3);
      sink.write("789", 3);
      sink.done(); // No more data
      return true; // return 'false' if you want to cancel the process.
    }
  );
});

With trailer:

svr.Get("/chunked", [&](const Request& req, Response& res) {
  res.set_header("Trailer", "Dummy1, Dummy2");
  res.set_chunked_content_provider(
    "text/plain",
    [](size_t offset, DataSink &sink) {
      sink.write("123", 3);
      sink.write("345", 3);
      sink.write("789", 3);
      sink.done_with_trailer({
        {"Dummy1", "DummyVal1"},
        {"Dummy2", "DummyVal2"}
      });
      return true;
    }
  );
});

'Expect: 100-continue' handler

By default, the server sends a 100 Continue response for an Expect: 100-continue header.

// Send a '417 Expectation Failed' response.
svr.set_expect_100_continue_handler([](const Request &req, Response &res) {
  return StatusCode::ExpectationFailed_417;
});
// Send a final status without reading the message body.
svr.set_expect_100_continue_handler([](const Request &req, Response &res) {
  return res.status = StatusCode::Unauthorized_401;
});

Keep-Alive connection

svr.set_keep_alive_max_count(2); // Default is 5
svr.set_keep_alive_timeout(10);  // Default is 5

Timeout

svr.set_read_timeout(5, 0); // 5 seconds
svr.set_write_timeout(5, 0); // 5 seconds
svr.set_idle_interval(0, 100000); // 100 milliseconds

Set maximum payload length for reading a request body

svr.set_payload_max_length(1024 * 1024 * 512); // 512MB

[!NOTE] When the request body content type is 'www-form-urlencoded', the actual payload length shouldn't exceed CPPHTTPLIB_FORM_URL_ENCODED_PAYLOAD_MAX_LENGTH.

Server-Sent Events

Please see Server example and Client example.

Default thread pool support

ThreadPool is used as a default task queue, and the default thread count is 8, or std:🧵:hardware_concurrency(). You can change it with CPPHTTPLIB_THREAD_POOL_COUNT.

If you want to set the thread count at runtime, there is no convenient way... But here is how.

svr.new_task_queue = [] { return new ThreadPool(12); };

You can also provide an optional parameter to limit the maximum number of pending requests, i.e. requests accept()ed by the listener but still waiting to be serviced by worker threads.

svr.new_task_queue = [] { return new ThreadPool(/*num_threads=*/12, /*max_queued_requests=*/18); };

Default limit is 0 (unlimited). Once the limit is reached, the listener will shutdown the client connection.

Override the default thread pool with yours

You can supply your own thread pool implementation according to your need.

class YourThreadPoolTaskQueue : public TaskQueue {
public:
  YourThreadPoolTaskQueue(size_t n) {
    pool_.start_with_thread_count(n);
  }

  virtual bool enqueue(std::function<void()> fn) override {
    /* Return true if the task was actually enqueued, or false
     * if the caller must drop the corresponding connection. */
    return pool_.enqueue(fn);
  }

  virtual void shutdown() override {
    pool_.shutdown_gracefully();
  }

private:
  YourThreadPool pool_;
};

svr.new_task_queue = [] {
  return new YourThreadPoolTaskQueue(12);
};

Client

#include <httplib.h>
#include <iostream>

int main(void)
{
  httplib::Client cli("localhost", 1234);

  if (auto res = cli.Get("/hi")) {
    if (res->status == StatusCode::OK_200) {
      std::cout << res->body << std::endl;
    }
  } else {
    auto err = res.error();
    std::cout << "HTTP error: " << httplib::to_string(err) << std::endl;
  }
}

[!TIP] Constructor with scheme-host-port string is now supported!

httplib::Client cli("localhost");
httplib::Client cli("localhost:8080");
httplib::Client cli("http://localhost");
httplib::Client cli("http://localhost:8080");
httplib::Client cli("https://localhost");
httplib::SSLClient cli("localhost");

Error code

Here is the list of errors from Result::error().

enum Error {
  Success = 0,
  Unknown,
  Connection,
  BindIPAddress,
  Read,
  Write,
  ExceedRedirectCount,
  Canceled,
  SSLConnection,
  SSLLoadingCerts,
  SSLServerVerification,
  UnsupportedMultipartBoundaryChars,
  Compression,
  ConnectionTimeout,
};

GET with HTTP headers

httplib::Headers headers = {
  { "Accept-Encoding", "gzip, deflate" }
};
auto res = cli.Get("/hi", headers);

or

auto res = cli.Get("/hi", {{"Accept-Encoding", "gzip, deflate"}});

or

cli.set_default_headers({
  { "Accept-Encoding", "gzip, deflate" }
});
auto res = cli.Get("/hi");

POST

res = cli.Post("/post", "text", "text/plain");
res = cli.Post("/person", "name=john1&note=coder", "application/x-www-form-urlencoded");

POST with parameters

httplib::Params params;
params.emplace("name", "john");
params.emplace("note", "coder");

auto res = cli.Post("/post", params);

or

httplib::Params params{
  { "name", "john" },
  { "note", "coder" }
};

auto res = cli.Post("/post", params);

POST with Multipart Form Data

httplib::MultipartFormDataItems items = {
  { "text1", "text default", "", "" },
  { "text2", "aωb", "", "" },
  { "file1", "h\ne\n\nl\nl\no\n", "hello.txt", "text/plain" },
  { "file2", "{\n  \"world\", true\n}\n", "world.json", "application/json" },
  { "file3", "", "", "application/octet-stream" },
};

auto res = cli.Post("/multipart", items);

PUT

res = cli.Put("/resource/foo", "text", "text/plain");

DELETE

res = cli.Delete("/resource/foo");

OPTIONS

res = cli.Options("*");
res = cli.Options("/resource/foo");

Timeout

cli.set_connection_timeout(0, 300000); // 300 milliseconds
cli.set_read_timeout(5, 0); // 5 seconds
cli.set_write_timeout(5, 0); // 5 seconds

Receive content with a content receiver

std::string body;

auto res = cli.Get("/large-data",
  [&](const char *data, size_t data_length) {
    body.append(data, data_length);
    return true;
  });
std::string body;

auto res = cli.Get(
  "/stream", Headers(),
  [&](const Response &response) {
    EXPECT_EQ(StatusCode::OK_200, response.status);
    return true; // return 'false' if you want to cancel the request.
  },
  [&](const char *data, size_t data_length) {
    body.append(data, data_length);
    return true; // return 'false' if you want to cancel the request.
  });

Send content with a content provider

std::string body = ...;

auto res = cli.Post(
  "/stream", body.size(),
  [](size_t offset, size_t length, DataSink &sink) {
    sink.write(body.data() + offset, length);
    return true; // return 'false' if you want to cancel the request.
  },
  "text/plain");

Chunked transfer encoding

auto res = cli.Post(
  "/stream",
  [](size_t offset, DataSink &sink) {
    sink.os << "chunked data 1";
    sink.os << "chunked data 2";
    sink.os << "chunked data 3";
    sink.done();
    return true; // return 'false' if you want to cancel the request.
  },
  "text/plain");

With Progress Callback

httplib::Client cli(url, port);

// prints: 0 / 000 bytes => 50% complete
auto res = cli.Get("/", [](uint64_t len, uint64_t total) {
  printf("%lld / %lld bytes => %d%% complete\n",
    len, total,
    (int)(len*100/total));
  return true; // return 'false' if you want to cancel the request.
}
);

progress

Authentication

// Basic Authentication
cli.set_basic_auth("user", "pass");

// Digest Authentication
cli.set_digest_auth("user", "pass");

// Bearer Token Authentication
cli.set_bearer_token_auth("token");

[!NOTE] OpenSSL is required for Digest Authentication.

Proxy server support

cli.set_proxy("host", port);

// Basic Authentication
cli.set_proxy_basic_auth("user", "pass");

// Digest Authentication
cli.set_proxy_digest_auth("user", "pass");

// Bearer Token Authentication
cli.set_proxy_bearer_token_auth("pass");

[!NOTE] OpenSSL is required for Digest Authentication.

Range

httplib::Client cli("httpbin.org");

auto res = cli.Get("/range/32", {
  httplib::make_range_header({{1, 10}}) // 'Range: bytes=1-10'
});
// res->status should be 206.
// res->body should be "bcdefghijk".
httplib::make_range_header({{1, 10}, {20, -1}})      // 'Range: bytes=1-10, 20-'
httplib::make_range_header({{100, 199}, {500, 599}}) // 'Range: bytes=100-199, 500-599'
httplib::make_range_header({{0, 0}, {-1, 1}})        // 'Range: bytes=0-0, -1'

Keep-Alive connection

httplib::Client cli("localhost", 1234);

cli.Get("/hello");         // with "Connection: close"

cli.set_keep_alive(true);
cli.Get("/world");

cli.set_keep_alive(false);
cli.Get("/last-request");  // with "Connection: close"

Redirect

httplib::Client cli("yahoo.com");

auto res = cli.Get("/");
res->status; // 301

cli.set_follow_location(true);
res = cli.Get("/");
res->status; // 200

Use a specific network interface

[!NOTE] This feature is not available on Windows, yet.

cli.set_interface("eth0"); // Interface name, IP address or host name

Compression

The server can apply compression to the following MIME type contents:

  • all text types except text/event-stream
  • image/svg+xml
  • application/javascript
  • application/json
  • application/xml
  • application/xhtml+xml

Zlib Support

'gzip' compression is available with CPPHTTPLIB_ZLIB_SUPPORT. libz should be linked.

Brotli Support

Brotli compression is available with CPPHTTPLIB_BROTLI_SUPPORT. Necessary libraries should be linked. Please see https://github.com/google/brotli for more detail.

Compress request body on client

cli.set_compress(true);
res = cli.Post("/resource/foo", "...", "text/plain");

Compress response body on client

cli.set_decompress(false);
res = cli.Get("/resource/foo", {{"Accept-Encoding", "gzip, deflate, br"}});
res->body; // Compressed data

Use poll instead of select

select system call is used as default since it's more widely supported. If you want to let cpp-httplib use poll instead, you can do so with CPPHTTPLIB_USE_POLL.

Split httplib.h into .h and .cc

$ ./split.py -h
usage: split.py [-h] [-e EXTENSION] [-o OUT]

This script splits httplib.h into .h and .cc parts.

optional arguments:
  -h, --help            show this help message and exit
  -e EXTENSION, --extension EXTENSION
                        extension of the implementation file (default: cc)
  -o OUT, --out OUT     where to write the files (default: out)

$ ./split.py
Wrote out/httplib.h and out/httplib.cc

NOTE

g++

g++ 4.8 and below cannot build this library since <regex> in the versions are broken.

Windows

Include httplib.h before Windows.h or include Windows.h by defining WIN32_LEAN_AND_MEAN beforehand.

#include <httplib.h>
#include <Windows.h>
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <httplib.h>

[!NOTE] cpp-httplib officially supports only the latest Visual Studio. It might work with former versions of Visual Studio, but I can no longer verify it. Pull requests are always welcome for the older versions of Visual Studio unless they break the C++11 conformance.

[!NOTE] Windows 8 or lower, Visual Studio 2013 or lower, and Cygwin and MSYS2 including MinGW are neither supported nor tested.

License

MIT license (© 2024 Yuji Hirose)

Special Thanks To

These folks made great contributions to polish this library to totally another level from a simple toy!

libcpr/cpr

2024年5月29日 10:10

C++ Requests: Curl for People, a spiritual port of Python Requests.


C++ Requests: Curl for People

Documentation CI Gitter

Announcements

Supported Releases

Release Min. C++ Standard Status Notes
master cpp17 alt text
1.10.x cpp17 alt text
1.9.x cpp11 alt text Supported until 01.01.2025
<= 1.8.x cpp11 alt text

TLDR

C++ Requests is a simple wrapper around libcurl inspired by the excellent Python Requests project.

Despite its name, libcurl's easy interface is anything but, and making mistakes, misusing it is a common source of error and frustration. Using the more expressive language facilities of C++17 (or C++11 in case you use cpr < 1.10.0), this library captures the essence of making network calls into a few concise idioms.

Here's a quick GET request:

#include <cpr/cpr.h>

int main(int argc, char** argv) {
    cpr::Response r = cpr::Get(cpr::Url{"https://api.github.com/repos/whoshuu/cpr/contributors"},
                      cpr::Authentication{"user", "pass", cpr::AuthMode::BASIC},
                      cpr::Parameters{{"anon", "true"}, {"key", "value"}});
    r.status_code;                  // 200
    r.header["content-type"];       // application/json; charset=utf-8
    r.text;                         // JSON text string
    return 0;
}

And here's less functional, more complicated code, without cpr.

Documentation

Documentation
You can find the latest documentation here. It's a work in progress, but it should give you a better idea of how to use the library than the tests currently do.

Features

C++ Requests currently supports:

  • Custom headers
  • Url encoded parameters
  • Url encoded POST values
  • Multipart form POST upload
  • File POST upload
  • Basic authentication
  • Bearer authentication
  • Digest authentication
  • NTLM authentication
  • Connection and request timeout specification
  • Timeout for low speed connection
  • Asynchronous requests
  • 🍪 support!
  • Proxy support
  • Callback interfaces
  • PUT methods
  • DELETE methods
  • HEAD methods
  • OPTIONS methods
  • PATCH methods
  • Thread Safe access to libCurl
  • OpenSSL and WinSSL support for HTTPS requests

Planned

For a quick overview about the planed features, have a look at the next Milestones.

Usage

CMake

fetch_content:

If you already have a CMake project you need to integrate C++ Requests with, the primary way is to use fetch_content. Add the following to your CMakeLists.txt.

include(FetchContent)
FetchContent_Declare(cpr GIT_REPOSITORY https://github.com/libcpr/cpr.git
                         GIT_TAG 3b15fa82ea74739b574d705fea44959b58142eb8) # Replace with your desired git commit from: https://github.com/libcpr/cpr/releases
FetchContent_MakeAvailable(cpr)

This will produce the target cpr::cpr which you can link against the typical way:

target_link_libraries(your_target_name PRIVATE cpr::cpr)

That should do it! There's no need to handle libcurl yourself. All dependencies are taken care of for you.
All of this can be found in an example here.

find_package():

If you prefer not to use fetch_content, you can download, build, and install the library and then use CMake find_package() function to integrate it into a project.

Note: this feature is feasible only if CPR_USE_SYSTEM_CURL is set. (see #645)

git clone https://github.com/libcpr/cpr.git
cd cpr && mkdir build && cd build
cmake .. -DCPR_USE_SYSTEM_CURL=ON
cmake --build . --parallel
sudo cmake --install .

In your CMakeLists.txt:

find_package(cpr REQUIRED)
add_executable(your_target_name your_target_name.cpp)
target_link_libraries(your_target_name PRIVATE cpr::cpr)

Tests

cpr provides a bunch of tests that can be executed via the following commands.

git clone https://github.com/libcpr/cpr.git
cd cpr && mkdir build && cd build
cmake .. -DCPR_BUILD_TESTS=ON # There are other test related options like 'CPR_BUILD_TESTS_SSL' and 'CPR_BUILD_TESTS_PROXY'
cmake --build . --parallel
ctest -VV # -VV is optional since it enables verbose output

Bazel

Please refer to hedronvision/bazel-make-cc-https-easy.

Packages for Linux Distributions

Alternatively, you may install a package specific to your Linux distribution. Since so few distributions currently have a package for cpr, most users will not be able to run your program with this approach.

Currently, we are aware of packages for the following distributions:

If there's no package for your distribution, try making one! If you do, and it is added to your distribution's repositories, please submit a pull request to add it to the list above. However, please only do this if you plan to actively maintain the package.

NuGet Package

For Windows, there is also a libcpr NuGet package available. Currently, x86 and x64 builds are supported with release and debug configuration.

The package can be found here: NuGet.org

Requirements

The only explicit requirements are:

  • a C++17 compatible compiler such as Clang or GCC. The minimum required version of GCC is unknown, so if anyone has trouble building this library with a specific version of GCC, do let us know
  • in case you only have a C++11 compatible compiler available, all versions below cpr 1.9.x are for you. The 1.10.0 release of cpr switches to C++17 as a requirement.
  • If you would like to perform https requests OpenSSL and its development libraries are required.

Building cpr - Using vcpkg

You can download and install cpr using the vcpkg dependency manager:

git clone https://github.com/Microsoft/vcpkg.git
cd vcpkg
./bootstrap-vcpkg.sh
./vcpkg integrate install
./vcpkg install cpr

The cpr port in vcpkg is kept up to date by Microsoft team members and community contributors. If the version is out of date, please create an issue or pull request on the vcpkg repository.

Building cpr - Using Conan

You can download and install cpr using the Conan package manager. Setup your CMakeLists.txt (see Conan documentation on how to use MSBuild, Meson and others). An example can be found here.

The cpr package in Conan is kept up to date by Conan contributors. If the version is out of date, please create an issue or pull request on the conan-center-index repository.

❌
❌