2026年2月




建立一个测试项目,这个项目使用我编写的类似于 OpenClaw 的 AI Assistant, 我的目的是做出一个当前适合于华人的 AI Assistant, 所以对于微信和浏览器等操作做了强化, 当前使用这个 AI Assistant 需要使用 Mac 电脑,对于 LLM 这个程序支持多种,但我推荐一个很便宜的选择 Z.ai 可以购买一年 $26 的 GLM, 可以使用 GLM 4.7 flash 这个模型,针对当前这个 AI Assistant 可能已经够用了

今日速览

  1. Base44 Backend Platform:AI 应用的后台管家,一键搞定全栈部署。
  2. Toolspend:SaaS 支出追踪神器,告别浪费,省钱省心。
  3. NVIDIA PersonaPlex:能聊能演的全双工 AI,声音角色随你定制。
  4. JDoodle.ai MCP:和 ChatGPT 聊天就能建网站,实时预览超方便。
  5. PenguinBot AI:24/7 智能员工,把对话变成实际工作。
  6. Agent Bar:菜单栏里的 Claude 小助手,语音交互实时追踪。
  7. Marketing Agents Squad:250+ 营销 AI 代理,秒出专业方案。
  8. Enough Cream:手机摄像头帮你泡咖啡,奶油浓度刚刚好。
  9. chowder.dev:一个 API 搞定 OpenClaw 实例,部署快如闪电。
  10. Meteorite:macOS 菜单栏记事本,轻量快捷不打扰。

深度阅读

1. Base44 Backend Platform

这款神器能帮你轻松构建带 AI 代理的应用,省去繁琐的后端设置,让开发更高效。

  • 一条命令部署全栈应用,无需手动配置
  • 专为 Claude Code 和 Cursor 优化,AI 代理用技能替代复杂 API
  • 经过数百万生产应用考验,稳定可靠
  • 独立服务上线,开箱即用

热度:🔺407

Base44 Backend Platform
访问官网 Product Hunt 详情


2. Toolspend

别再为 SaaS 订阅和闲置许可证烧钱了!Toolspend 是你的技术栈指挥中心,帮你全面掌控支出。

  • 深度分析工具使用情况和消费模式,识别浪费
  • 自动发现未充分利用的座位和重复工具
  • 续订前智能提醒,避免隐形费用
  • 自动化采购流程,让你专注产品构建

热度:🔺396

Toolspend
访问官网 Product Hunt 详情


3. NVIDIA PersonaPlex

这款全双工对话 AI 能自然交流,支持定制声音和角色,让互动更生动。

  • 可应对打断和旁白,保持角色一致性
  • 在对话动态和任务执行上优于现有系统
  • 声音和角色高度可定制,适应不同场景
  • 实现自然流畅的人机交互

热度:🔺252

NVIDIA PersonaPlex
访问官网 Product Hunt 详情


4. JDoodle.ai MCP

想建网站?直接和 ChatGPT 或 Claude 聊天就行!JDoodle.ai 让你实时创建和预览应用。

  • 通过对话构建前端、后端或全栈应用
  • 项目在 JDoodle.ai 内实时更新,提供即时预览
  • 一键生成在线链接,快速发布
  • 支持迭代和问题修复,聊天驱动开发
  • 可集成数据库,功能全面

热度:🔺191

JDoodle.ai MCP
访问官网 Product Hunt 详情


5. PenguinBot AI

你的智能员工全天候待命,把对话转化为实际行动,解放你的双手。

  • 管理电子邮件、安排任务、创建文档自动化
  • 自动运行工作流程,后台持续运转
  • 自主规划执行,安全可靠
  • 24/7 运行,让你专注核心事务

热度:🔺171

PenguinBot AI
访问官网 Product Hunt 详情


6. Agent Bar

把 Claude Code 装进菜单栏!这个小助手提供原生界面,让桌面操作更轻松。

  • 选择项目后通过语音交互,实时查看工具调用
  • 批准或自动批准操作,灵活控制
  • 追踪令牌费用,成本一目了然
  • 桌面集成,无需切换窗口

热度:🔺139

Agent Bar
访问官网 Product Hunt 详情


7. Marketing Agents Squad

250+ AI 营销代理随时待命,帮你分担日常营销工作,秒出专业方案。

  • 每个代理都懂营销背景,无需额外培训
  • 描述目标后几秒钟内生成专业输出
  • 覆盖多种营销场景,灵活选择
  • 就像拥有天才实习生团队,效率倍增

热度:🔺138

Marketing Agents Squad
访问官网 Product Hunt 详情


8. Enough Cream

泡咖啡时总加多奶油?这款应用用手机摄像头帮你搞定,每次都是完美浓度。

  • 实时分析咖啡颜色,对比保存的偏好
  • 智能提示停止倒奶油的时机
  • 确保每次咖啡浓稠度一致
  • 简单易用,提升日常体验

热度:🔺129

Enough Cream
访问官网 Product Hunt 详情


9. chowder.dev

一个 API 就能启动和管理 OpenClaw 实例,部署快得飞起,基础设施全包。

  • 几秒钟内启动完全独立的 Claw 实例
  • 连接到 11 个消息通道,扩展性强
  • 支持安装技能、管理身份验证和持久化记忆
  • 与 OpenAI 兼容的 API,从零部署不到一分钟

热度:🔺129

chowder.dev
访问官网 Product Hunt 详情


10. Meteorite

专为 macOS 设计的菜单栏记事本,轻量快捷,让你随时捕捉灵感不打断工作流。

  • 快速记录笔记、任务和代码片段
  • 原生开发,键盘操作为主,高效流畅
  • 轻量级设计,不占用系统资源
  • 简约界面,无干扰体验

热度:🔺123

Meteorite
访问官网 Product Hunt 详情

美团没有护城河,各业务线被打的溃不成军,股价连破 52 周新低,哎 😔 难崩

团购业务被字节紧追不舍,已经达到美团团购 80% 体量,分别占比 55%(美团)和 45%(字节)。
外卖业务已经和淘宝闪购五五开,分别占比 50%(美团),45%(淘宝山沟),5%(京东外卖)。
酒旅,更是千年老二老三,携程系占比接近 80%.美团和其他加起来 20%。

股价连破 52 周新低,你觉得价格合适吗,你会抄底吗?

用的阿里云百炼大模型的 DeepSeek ,text-embedding-v4

开 32 个线程,失败率到 40%了。

阿里云的 RPM/TPM 限制的很低。

联系商务,商务放假了。

按照现在这个速度,2 亿数据跑完要半年了。

各位有没有批量处理数据向量化的好方法?

手持 MBP 16 2019; ROG 幻 16 翻转版 2023 ; iPad Pro 2021 m1 miniLED
最近想换台工作机( MBP 16 2019 实在是有点卡顿了),不太在意价格
职业属性:商务销售加产品经理,
主要工作场景:巨大的数据表(几十万行,50mb 左右的表);同时开十几个标签页(公司内部系统,客户系统,第三方系统),PPT,产品需求文档-word ,飞书,微信等等,主要还是文字工作以及简单的数据分析。
还是考虑换 Mac,喜欢原生的备忘录,提醒事项功能


犹豫 MBP 14 m5 还是 macbook air 13 m4;


怕的是 macbook pro 的 miniled 屏幕有光晕,幻 16 以及 ipad 的光晕实在是让人眼睛感觉没法对焦;
macboook air 没有 hdmi 接口,总感觉加个拓展坞,没那么方便。

内存 16g 够吗,目前工作机是 windows ,64g ;
储存空间目前暂定 512g ,应该加上百度网盘算是够用

今天是大年初一,江湖十年给读者朋友们拜年了,祝大家新年快乐!

又是新的一年,想必大家都没看春晚吧 😄,今天继续一年一度的用 Go 语言实现春晚魔术。

废话不多说,咱们直接看原理。

<!-- more -->

魔术原理揭秘

这个魔术的数学原理其实很简单,基于一个简单的恒等式:

设目标时间为 T
设观众说的两个数为 A 和 B
魔术师计算的第三个数为 C = T - (A + B)

那么:A + B + C = A + B + [T - (A + B)] = T

这里的 T 就是最终结果:2162227

  • 观众 A 说:1106
  • 观众 B 说:88396
  • 观众“乱按”的计算器显示:2072725
  • 相加结果:1106 + 88396 + 2072725 = 2162227

这个数字代表:2 月 16 日 22 时 27 分

理解了吗?

这里其实有个障眼法,就是魔术师现场找了三个观众“乱按”了几下,但其实谁也不确定他们按的什么,对不对,其实他们按的数字根本就没用上,而是计算器里已经预先计算出了目标时间 T 与 A + B 总和的差值。

没错,魔术这种东西就是这么朴实无华。

Go 语言实现魔术

那么接下来,就用 Go 语言来实现一个简单的计算器程序,来还原这个魔术。

首先定义一个魔术计算器:

// MagicCalculator 魔术计算器
type MagicCalculator struct {
    targetTime int    // 目标时间转换的数字
    timestamp  string // 实际时间字符串
}

接下来实现一个魔术计算器的构造方法:

// NewMagicCalculator 创建一个魔术计算器实例
func NewMagicCalculator() *MagicCalculator {
    // 获取当前时间
    now := time.Now()

    // 生成类似 "2162227" 的时间数字
    // 格式: 月(1-2 位) + 日(2 位) + 小时(2 位) + 分钟(2 位)
    month := int(now.Month())
    day := now.Day()
    hour := now.Hour()
    minute := now.Minute()

    // 构建时间字符串和数字
    timestamp := fmt.Sprintf("%d%02d%02d%02d", month, day, hour, minute)

    // 转换为整数
    target, _ := strconv.ParseInt(timestamp, 10, 64)

    return &MagicCalculator{
        targetTime: int(target),
        timestamp:  timestamp,
    }
}

当前时间 now 就是用来计算目标时间的,可以根据需要设定,这里直接使用当前时间。

target 是格式为 2162227 的时间数字,也就是咱们原理解析中的目标时间 T。

定义一个 计算魔术数字 T -(A + B)的方法:

// GetMagicNumber 计算魔术数字
func (mc *MagicCalculator) GetMagicNumber(num1, num2 int) int {
    // 魔术公式: target - (num1 + num2)
    return mc.targetTime - (num1 + num2)
}

最后就是定义一个交互式函数,它实现了:

  • 计算目标时间 T
  • 接收用户输入的 A、B
  • 计算观众“乱按”的第三个数字

源码如下:

func InteractiveMagic() {
    fmt.Println("=== 交互式魔术体验 ===")
    fmt.Println("请按照提示输入数字,我会展示魔术的原理")

    mc := NewMagicCalculator()

    var num1, num2 int
    fmt.Print("请输入第一个数: ")
    fmt.Scan(&num1)
    fmt.Print("请输入第二个数: ")
    fmt.Scan(&num2)

    fmt.Printf("\n你输入的是: %d 和 %d\n", num1, num2)

    magicNum := mc.GetMagicNumber(num1, num2)
    fmt.Printf("魔术数字(第三个数)是: %d\n", magicNum)

    fmt.Printf("\n验证: %d + %d + %d = %d\n", num1, num2, magicNum, mc.targetTime)
    fmt.Printf("这个数字代表的时间是: %s\n", mc.timestamp)
}

程序 main 入口:

func main() {
    InteractiveMagic()
}

验证魔术:

# 运行程序
$ go run main.go
=== 交互式魔术体验 ===
请按照提示输入数字,我会展示魔术的原理
请输入第一个数: 1106
请输入第二个数: 88396

你输入的是: 1106 和 88396
魔术数字(第三个数)是: 2081398

验证: 1106 + 88396 + 2081398 = 2170900
这个数字代表的时间是: 2170900

通过 go run main.go 运行程序,接下来根据提示分别输入两个数字,这里以春晚观众说的两个数字(110688396)为例,然后计算观众“乱按”的第三个数字(2081398),最终得到的目标时间是 2170900

没错,我在 2 月 17 日 09 时 00 分运行的程序。

总结

今天依旧使用 Go 语言简单实现了魔术小程序,看个乐子,开心最重要。

如果你有兴趣,完全可以通过聊天的方式让大模型生成一个带有前端界面的魔术计算器程序,体验 vibe coding 的乐趣。

本文完整代码示例我放在了 GitHub 上,欢迎点击查看。

25 年我的文章里吐槽了春晚魔术“降本增效”,在此给刘谦老师道个歉,是我冒犯了🤣之前对魔术一无所知。

25 年看了老罗采访刘谦的视频,对刘谦大佬肃然起敬 respect 🫡。

image.png

延伸阅读

联系我

7z2501-x64是 7-Zip 25.01 版本的 64 位安装包,7-Zip 是个压缩解压工具,能把文件打成 7z、zip、tar 等格式,压缩率高、速度也快,解压大文件比系统自带的压缩功能稳很多。

一、准备工作

  1. 下载安装包

    安装包下载:https://pan.quark.cn/s/4829834dd438

  2. 确认系统版本

    • 必须是 64 位 Windows(Win7/Win10/Win11 都行),32 位系统要用 32 位安装包。
  3. 用管理员身份运行(推荐)

    • 右键 7z2501-x64.exe→ 选“以管理员身份运行”,防止权限不足装不上。

二、安装步骤

  1. 双击 7z2501-x64.exe运行(如果右键过了就直接双击)。
  2. 第一次打开会弹出“用户账户控制”提示 → 点  “是”
  3. 进入安装向导,选语言(默认 English,有的版本有中文)→ 点  “OK”
  4. 阅读许可协议 → 选 “I Agree” → 点  “Next”
  5. 选安装类型:

    • 一般选 Install​ 直接装到默认位置(C:\Program Files\7-Zip),新手直接点  “Install” ​ 就行;
    • 想自己选位置就点 “Browse” 改路径(比如 D 盘)。
  6. 选关联文件类型(重要):

    • 建议勾上常用的:.7z.zip.rar.tar等,这样以后双击这些格式的文件会用 7-Zip 打开。
  7. 点  “Finish” ​ 完成安装。

三、首次使用与基本操作

  1. 安装完,右键任意文件或文件夹,会看到多出 “7-Zip” 菜单。
  2. 压缩:右键文件 → 7-Zip → “添加到压缩包” → 选格式(7z 压缩率高,zip 兼容性好)→ 点 “确定”。
  3. 解压:右键压缩包 → 7-Zip → “解压到当前文件夹” 或 “解压到 xxx\”(自动建同名文件夹)。
  4. 查看压缩包内容:右键压缩包 → 7-Zip → “打开压缩包”,不用完全解压就能看里面的文件。

1 ,前几天飞牛出事,一直在想我要装[群晖],还是弄回[PVE 系统],然后弄 All in one.
随即我又尝试了 PVE ,最终再次倒在了 OpenWRT (之前也是倒在这里,感觉装了很有用,但是装完又不知道怎么继续配置下去了,还有概率导致断网),用起来有点头疼。
感觉不装 OpenWRT 还不如不用 PVE 的 All in one, 徒增功耗的同时稳定性不如单系统或者群晖。

2 ,尝试去装黑群晖,格式化的时候忘记我的影视盘资源忘记迁移了,直接全部格式化了。。。

我是用的 12900HX 魔改的 Cpu ,貌似支持不了 SA6400 尝试了三次卡在最后装系统的那一步。(我看到 CHH 论坛有 13500T 还是 12500T 装上的,按理来说我这个也没问题才对)
还浪费了十块钱买了个 洗白码,最后没用上···,文章末尾我会分享出去,也不知道能不能帮助到别人。

3 ,最后我想了想,我装 WinNAS 可以让电脑随时变成游戏机,我还不如直接 WIn 了,在补课完 WinNas 的优缺点后果断选择。
①windows 天然的游戏机,而且还不怕虚拟机检测,我的 CPU 核显能力还是不错的,开个 720P 游戏挂挂毫无问题。
②电脑 启动速度巨快无比,即便不开机也能超快速度恢复。
③世界级的安全服务,甚至还有 Bitlocker 加密。
缺点可能就是长时间运行不如 Linux 系统了?不过我没有装 Windows Server 系统,装的是 Win10 LTSC 2021 .

哎,最后还得是 WinNAS ,基本功能也够用了,以后朋友来家里,插个显卡就变游戏机了,待机功耗问题用网络唤醒也轻松解决了。
而且影视盘的这件事也让我知道,我对影视的需求似乎并没有那么离谱。。



以下是买的黑群晖的洗白码,没用上,以后估计也不会用了。
所以?分享给其他需要的人?(也不知道这样共享会怎么样)

[已更新至最新版:RR-26.2.0(2026 年 2 月更新)
黑群晖 2026 年最新 U 盘引导和工具(包含洗白码和洗白教程)

下载地址①: https://pan.baidu.com/s/5SWUlHgcd_A-cqfpg43PgsA (百度网盘)

下载地址②: https://share.weiyun.com/5sG7qgTb (腾讯微云)推荐!!无需客户端。

下载地址③: https://ljk.myds.me:5001/sharing/2UY78vEGW (本地下载)备用

{注意:请尽快复制此页面内容和链接保存,2 小时后本链接失效}

群晖洗白码:

3622xs+
SN=2190SQRNRFYGD MAC1=9009D0048C92 MAC2=9009D0048C93

SA6400
SN=2277UMR8HWA07 MAC1=9009D02A95D1 MAC2=9009D02A95D2

附几个 DS918+ 全白码
S/N=178CPDN567913 MAC=0011327B4E49
S/N=178CPDN567314 MAC=0011327B5619
S/N=178CPDN567015 MAC=0011327B5DE9

1 、洗白教程: http://www.nas50.cn/?id=10
2 、更多群晖教程,请访问官方网站: https://www.nas50.cn
3 、版本一直在更新,请前往我的哔哩哔哩主页: https://space.bilibili.com/439836524 观看最新视频教程
4 、最近版已经解决网络出错问题。

只提供资源和教程,不提供技术支持。 本资源持续更新·2026.02.10 ]

在编程中,我们经常要处理字符和字符串,为了方便操作字符和字符串,C语言标准库中提供了一系列库函数。

1 字符函数

1.1 字符分类函数

C语言中有一系列的函数是专门做字符分类的,也就是一个字符是属于什么类型的字符的。这些函数的使用都需要包含一个头文件ctype.h

例如islowerisupper等,以islower为例:

int islower (int c);

islower能够判断参数部分的c是否是小写字母。通过返回值来说明是否是小写字母,如果是小写字母就返回非0的整数,如果不是小写字母,则返回0。关于(int c),要注意到字符的本质是一个ASCII码值,这样的写法并没有问题。

1.2 字符转换函数

在之前,要一个字符大小写转换打印,用的是字符+/-32来实现的,例如:大写转小写就加上32、小写转大写就减去32(参见ASCII码相关知识)。现在,我们可以用以下库函数来更简洁的解决。

C语言提供了2个字符转换函数:

int tolower (int c);//将参数传进去的大写字母转小写
int toupper (int c);//将参数传进去的小写字母转大写

举个例子:

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <ctype.h>
int main()
{
    char i = 'a';
    //i = i - 32;
    i = toupper(i);
    printf("%c\n", i);
    return 0;
}

2 字符串函数

1 strlen的使用和模拟实现

size_t strlen ( const char * str );
  • 字符串以'\0'作为结束标志,strlen函数返回的是在字符串中'\0'前面出现的字符个数(不包

'\0')。

  • 参数指向的字符串必须要以'\0'结束。
  • 函数的返回值为size_t,是无符号的(⭐)。
  • strlen的使用需要包含头文件string.h

strlen的模拟实现:

#define _CRT_SECURE_NO_WARNINGS 1
#include <string.h>
#include <stdio.h>
#include <assert.h>

//模拟实现strlen
size_t my_strlen1(const char* str)
{
    assert(str != NULL);
    size_t n = 0;
    while (*str != '\0')
    {
        n++;
        str++;
    }
    return n;
}

size_t my_strlen2(const char* str)
{
    assert(str != NULL);
    char* p = str;
    while (*p)
    {
        p++;
    }
    return p - str;
}

size_t my_strlen3(const char* str)
{
    assert(str != NULL);
    if (*str)
    {
        return 1 + my_strlen3(str + 1);
    }
    else
    {
        return 0;
    }
}

int main()
{
    char arr[] = { "abcdef" };
    size_t r = strlen(arr);
    size_t r1 = my_strlen1(arr);
    size_t r2 = my_strlen2(arr);
    size_t r3 = my_strlen3(arr);
}

2 strcpy的使用和模拟实现

char * strcpy ( char * destination, const char * source );
  • 字符串复制。Copies the C string pointed by source into the array pointed by destination, including the terminating null character (and stopping at that point).
  • 源字符串必须以'\0'结束。
  • 会将源字符串中的'\0'拷贝到目标空间。
  • 目标空间必须足够大,以确保能存放源字符串。
  • 目标空间必须可修改。

strcpy的模拟实现:

#define _CRT_SECURE_NO_WARNINGS 1
#include <string.h>
#include <stdio.h>
#include <assert.h>

//模拟实现strcpy
//char* my_strcpy(char* des, const char* src)
//{
//    assert(des != NULL && src != NULL);
//    char* ret = des;
//    while (*src)
//    {
//        *des = *src;
//        des++;
//        src++;
//    }
//    *des = '\0';
//    return ret;
//}

char* my_strcpy(char* des, const char* src)
{
    assert(des != NULL && src != NULL);
    char* ret = des;
    while (*des++ = *src++)
    {
        ;
    }
    return ret;
}

int main()
{
    char arr1[20] = { "abcdef" };
    char arr2[20] = {"xxxxxxxxxxxxxxxx"};
    my_strcpy(arr2, arr1);
}

3 strcat的使用和模拟实现

char * strcat ( char * destination, const char * source );
  • 字符串拼接。Appends a copy of the source string to the destination string. The terminating null character in destination is overwritten by the first character of source, and a null-character is included at the end of the new string formed by the concatenation of both in destination.
  • 源字符串必须以'\0'结束。
  • 目标字符串中也得有'\0',否则没办法知道追加从哪里开始。
  • 目标空间必须有足够的大,能容纳下源字符串的内容。
  • 目标空间必须可修改。
  • 将该函数用于字符串自己给自己追加是不合适的,其结果未定义。

strcat模拟实现:

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>
#include <assert.h>
char* my_strcat(char* des, const char* src)
{
    assert(des && src);
    char* ret = des;
    while (*des != '\0')
    {
        des++;
    }
    while (*des++ = *src++)
    {
        ;
    }
    return ret;
}

int main()
{
    char a[20] = { "Hello \0xxxxxxxxxxx" };//目标字符串要有足够位置
    char b[10] = { "world" };
    //strcat(a, b);
    my_strcat(a, b);
    printf("%s\n", a);
}

4 strcmp的使用和模拟实现

int strcmp ( const char * str1, const char * str2 );
  • 字符串比较。This function starts comparing the first character of each string. If they are equal to each other, it continues with the following pairs until the characters differ or until a terminating null-character is reached.
  • 判断两个字符串的大小:比较两个字符串中对应位置上字符ASCII码值的大小。
  • 标准规定的返回值要求如下:

strcmp模拟实现:

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>
#include <assert.h>
int my_strcmp1(const char* str1, const char* str2)
{
    assert(str1 && str2);
    while (*str1 == *str2)
    {
        if (*str1 == '\0')
            return 0;
        str1++;
        str2++;
    }
    return (*str1 - *str2);
}

int my_strcmp2(const char* str1, const char* str2)
{
    assert(str1 && str2);
    while (*str1 == *str2)
    {
        if (*str1 == '\0')
            return 0;
        str1++;
        str2++;
    }
    if (*str1 > *str2)
        return 1;
    else
        return -1;
}

int main()
{
    char a1[] = { "abcdef" };
    char a2[] = { "abq" };
    int r = strcmp(a1, a2);
    int r1 = my_strcmp1(a1, a2);
    int r2 = my_strcmp2(a1, a2);
    return 0;
}

strcpystrcatstrcmp三个函数有对应的更安全的版本(要多传一个参数),它们分别是strncpystrncatstrncmp

5 strncpy函数

char * strncpy ( char * destination, const char * source, size_t num );
  • Copies the first num characters of source to destination. If the end of the source C string (which is signaled by a null-character) is found before num characters have been copied,destination is padded with zeros until a total of num characters have been written to it.
  • 拷贝num个字符从源字符串到目标空间。
  • 如果源字符串的长度小于num,则拷贝完源字符串之后,在目标的后边追加0,直到num个。

6 strncat函数

char * strncat ( char * destination, const char * source, size_t num );
  • Appends the first num characters of source to destination, plus a terminating null-character.(将source指向字符串的前num个字符追加到destination指向的字符串末尾,再追加一个\0字符)。
  • If the length of the C string in source is less than num, only the content up to the terminating null-character is copied.(如果source指向的字符串的长度小于num的时候,只会将字符串中到\0的内容追加到destination指向的字符串末尾)。

7 strncmp函数

int strncmp ( const char * str1, const char * str2, size_t num );
  • Compares up to num characters of the C string str1 to those of the C string str2.This function starts comparing the first character of each string. If they are equal to each other, it continues with the following pairs until the characters differ, until a terminating null-character is reached, or until num characters match in both strings, whichever happens first.
  • 比较str1str2的前num个字符,如果相等就继续往后比较,最多比较num个字母,如果提前发现不一样,就提前结束。返回值标准参照strcmp函数。

8 strstr的使用和模拟实现

const char * strstr ( const char * str1, const char * str2 );
  • Returns a pointer to the first occurrence of str2 in strl, ora null pointer if str2 is not part of strl.(函数返回字符串str2在字符串str1中第一次出现的位置)。
  • The matching process does not include the terminating null-characters, but it stops there.(字符串的比较匹配不包含\0字符,以\0作为结束标志)。
  • 返回值规定:A pointer to the first occurrence in str1 of the entire sequence of characters specified in str2, or a null pointer if the sequence is not present in str1.

strstr模拟实现:

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>
#include <assert.h>
char* my_strstr(const char* str1, const char* str2)
{
    assert(str1 && str2);
    const char* cur = str1;//记录比较的起始位置
    const char* s1 = NULL;//用s1在str1中遍历
    const char* s2 = NULL;//用s2在str2中遍历
    
    //特殊情况:str2是一个空字符串
    if (*str2 == '\0')
        return str1;

    while (*cur)
    {
        s1 = cur;
        s2 = str2;
        while (*s1 && *s2 && *s1 == *s2)
        {
            s1++;
            s2++;
        }
        if (*s2 == '\0')
            return (char*)cur;
        cur++;
    }
    return NULL;//找不到
}

int main()
{
    char a[] = { "abbbcdef" };
    char b[] = { "bbc" };
    //char* r = strstr(a, b);
    char* r = my_strstr(a, b);
    printf("%s\n", r);
}

示意图:

str1str2分别记录字符串a、b的起始位置;cur记录比较的起始位置;s1s2用于遍历,完成一次比较后分别靠curstr2复位。

另,字符串匹配算法——KMP算法。

9 strtok函数的使用

char * strtok ( char * str, const char * sep );
  • sep参数指向一个字符串,定义了用作分隔符的字符集合。
  • 第一个参数指定一个字符串,它包含了0个或者多个由sep字符串中一个或者多个分隔符分割的标记。
  • strtok函数找到str中的下一个标记,并将其用\0结尾,返回一个指向这个标记的指针。(注:strtok函数会改变被操作的字符串,所以被strtok函数切分的字符串一般都是临时拷贝的内容并且可修改。)
  • strtok函数的第一个参数不为NULL,函数将找到str中第一个标记,strtok函数将保存它在字符串中的位置。
  • strtok函数的第一个参数为NULL,函数将在同一个字符串中被保存的位置开始,查找下一个标记。
  • 如果字符串中不存在更多的标记,则返回NULL指针。

举个例子:

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>


int main()
{
    char arr[] = "zpw@bitedu.net.hehe";
    char buf[20] = {0};//可以修改
    strcpy(buf, arr);
    //zpw\0bitedu\0net
    const char* p = "@.";
    char* r = NULL;
    for (r = strtok(buf, p); r != NULL; r = strtok(NULL, p))
    {
        printf("%s\n", r);
    }

    //这样用是不合适的
    //char* r1 = strtok(buf, p);
    //printf("%s\n", r1);//zpw
    //r1 = strtok(NULL, p);
    //printf("%s\n", r1);//bitedu
    //r1 = strtok(NULL, p);
    //printf("%s\n", r1);//net
    return 0;
}

10 strerrorperror函数的使用

strerror函数可以把参数部分错误码对应的错误信息的字符串地址返回来。

char * strerror ( int errnum );

在不同的系统和C语言标准库的实现中都规定了一些错误码,一般是放在errno.h这个头文件中说明的,C语言程序启动的时候就会使用一个全局变量errno来记录程序的当前错误码,只不过程序启动的时候errno是0,表示没有错误,当我们在使用标准库中的函数的时候发生了某种错误,就会将对应的错误码,存放在errno中,而一个错误码的数字是整数很难理解是什么意思,所以每一个错误码都是有对应的错误信息的。strerror函数就可以将错误对应的错误信息字符串的地址返回。

除此之外,还有一个函数perror,它不需要传入错误码,会直接将错误信息打印出来。

void perror ( const char * str );

perror函数打印完参数部分的字符串后,再打印一个冒号和一个空格,再打印错误信息。

举个例子:

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>
#include <errno.h>

int main()
{
    //打开文件
    FILE* pf = fopen("test.txt", "r");//以读的形式打开test.txt文件,如果文件不存在,则打开失败。
    if (pf == NULL)
    {
        //打开文件失败了
        perror("错误信息是");//: xxxx
        printf("错误信息是: %s\n", strerror(errno));
        return 1;
    }
    //往下走了
    //...
    return 0;
}

最近线上一个站点频繁出现 Cloudflare 522,刚开始以为是服务器资源不够,结果一路排查下来发现根本不是这么回事。

这篇记录把整个排查过程、判断逻辑、容易误判的点、以及最终原因梳理一下,给遇到类似问题的朋友一个参考。


一、522 到底是什么?

Cloudflare 官方解释:

522 = 连接源站超时( Connection timed out )

本质是:

  • Cloudflare 节点已经接收到用户请求
  • Cloudflare 尝试连接你的源站服务器
  • 在规定时间内没有完成 TCP 建立

也就是说:

不是 Cloudflare 问题,是 Cloudflare 到你服务器之间的链路出问题。

重点是:

不是页面慢,是“连不上”


二、常见误区

很多人第一反应是:

  • 服务器挂了?
  • CPU 100%?
  • 内存爆了?
  • Nginx 崩了?

但实际上 522 更多时候和以下有关:

  1. 源站防火墙拦截了 Cloudflare IP
  2. 源站带宽跑满
  3. TCP backlog 满
  4. 丢包严重
  5. 线路回程异常
  6. 云厂商侧网络抖动

服务器本身未必有问题。


三、第一步:确认服务器是否“真的挂了”

先从最简单的开始。

在服务器上执行:

top

看:

  • CPU 是否打满
  • load average 是否异常
  • 是否有异常进程

然后:

free -m

确认内存没有被打爆。

接着看 Nginx:

systemctl status nginx

如果 nginx 正常,CPU 正常,内存正常,说明:

服务器没挂


四、第二步:是否防火墙拦了 Cloudflare

Cloudflare 有固定 IP 段。

可以用:

iptables -L -n

或者

ufw status

确认没有限制 CF IP 。

有时候 fail2ban 会误封。


五、第三步:是否 TCP 队列满

这一步很多人忽略。

查看:

netstat -an | grep SYN_RECV | wc -l

如果大量 SYN_RECV ,说明半连接队列爆了。

再看:

sysctl net.core.somaxconn

如果值太小(默认 128 ),在高并发下可能不够。

可以调整:

net.core.somaxconn = 65535
net.ipv4.tcp_max_syn_backlog = 65535


六、第四步:是否带宽跑满

执行:

iftop

如果带宽已经满载,比如 100M 打满。

Cloudflare 连过来就会超时。

很多人忽略:

100M 带宽在高峰时段其实很容易满。

尤其是:

  • 视频站
  • 下载站
  • 被扫站


七、第五步:用 mtr 看丢包

这是关键。

在本地执行:

mtr -rw 你的服务器 IP

看:

  • 是否某一跳开始丢包
  • 是否晚高峰严重
  • 是否回程绕路

有一次排查发现:

回程绕美西

延迟从 20ms 变成 180ms 。

Cloudflare 到源站那一段开始丢包。

服务器本身完全正常。


八、真实案例:问题不在服务器

那次问题最终定位:

  • CPU 20%
  • 内存正常
  • nginx 正常
  • 带宽没满
  • TCP 队列正常

但 mtr 显示:

某骨干节点开始 20% 丢包。

而且:

晚上 8 点之后必出 522

典型线路拥堵。


九、Cloudflare 522 和 524 的区别

很多人混淆。

  • 522:TCP 连不上
  • 524:连上了,但响应超时

524 更像后端慢。
522 更像网络层问题。


十、如何系统判断 522 原因?

我后来总结一个判断流程:

1️⃣ 本机资源正常?
2️⃣ nginx 是否监听?
3️⃣ 防火墙是否拦 CF ?
4️⃣ TCP 队列是否满?
5️⃣ 带宽是否满?
6️⃣ mtr 是否丢包?
7️⃣ 是否固定时间段出现?

只要按顺序走,不会乱。


十一、一个关键点:线路稳定性比延迟更重要

很多人只看 ping 延迟。

其实:

稳定性 > 低延迟

20ms 但偶尔丢包,比 40ms 稳定更糟。

尤其是被 Cloudflare 代理后,回程异常更容易触发 522 。


十二、几个实用优化建议

① 开启 keepalive

keepalive_timeout 65;

② 调整 worker_connections

worker_connections 65535;

③ 调整系统文件数

ulimit -n 100000

④ 合理选择线路

这个真的比堆配置重要。


十三、结论

522 不等于服务器不行。

大多数时候是:

  • 网络层问题
  • 带宽瓶颈
  • 回程异常
  • 丢包

真正需要学会的是:

用数据判断,而不是凭感觉。


十四、我的教训

那次我第一反应是:

加配置

结果完全没用。

真正解决问题的是:

换了一条更稳定的线路

服务器规格没变。

问题消失。


如果有人最近也在被 522 折磨,可以按上面的顺序排查。

别一上来就重装系统,也别盲目升级配置。

大概率不是你想的那个问题。

 1. 准备工作

  • 先看系统对不对版

    打开终端,敲两个命令确认一下:

    cat /etc/os-release
    uname -m
输出里有 `Kylin Linux`和 `x86_64`就没问题。
  • 找到 RPM 包在哪

    安装包下载:https://pan.quark.cn/s/3bc38adb2b2a  ,假设你把包下载到了 /home/你的用户名/下载/目录。先切换过去,确认文件在:

    cd /home/你的用户名/下载
    ls -l zlib-devel-1.2.11-20.ky10.x86_64.rpm
能看到文件信息就说明位置对了。


🛠️ 2. 开始安装

还是老规矩,推荐用第二种方法,能自动处理依赖,少踩坑。

方法一:用 rpm命令直接装

简单直接,但缺依赖得自己找。

  1. 执行安装

    在 RPM 包所在目录运行:

    sudo rpm -ivh zlib-devel-1.2.11-20.ky10.x86_64.rpm
-   `-i`安装
-   `-v`看过程
-   `-h`显示进度条
  1. 缺啥补啥

    如果报错了,一般是提示缺依赖,比如 zlib本身。按提示把缺的包装上,再重新执行上面命令。

方法二:用 dnf或 yum装 (推荐)

自动解决依赖,省心。

  1. 执行安装

    在包所在目录执行:

    # 如果系统用 dnf
    sudo dnf install ./zlib-devel-1.2.11-20.ky10.x86_64.rpm
    
    # 如果系统用 yum
    sudo yum localinstall zlib-devel-1.2.11-20.ky10.x86_64.rpm
输密码后它会分析依赖,问是否继续,输入 `y`回车就成。


✅ 3. 检查是否装好

装完后验证一下:

rpm -q zlib-devel

如果输出 zlib-devel-1.2.11-20.ky10.x86_64,就说明安装成功。

Shadcn,这款广受欢迎的开源 UI 组件库,发布了一款可视化项目构建工具,可通过 npx shadcn create 命令来使用。该工具内置完善的主题系统,支持多种框架,并采用“设计优先”的方式来创建新项目。

create 命令(ui.shadcn.com/create)提供了一个可视化界面,让开发者在编写第一行代码之前就能完成整个项目的自定义配置。该工具支持 Next.jsViteTanStack Start 框架,可完整配置主题、组件库、图标集和设计系统。

其核心功能是实时预览和自定义项目设计系统的各个方面。开发者可以选择 Radix UIBase UI 作为组件基础,从多种视觉风格中选择(包括热门的 Nova 预设),配置基础颜色和主题,选择 Lucide 等图标库,自定义字体和圆角值,调整菜单颜色和强调色。界面还提供“随机生成”功能,可快速生成随机设计组合,帮助开发者探索不同的视觉风格方向。

该工具会引导用户选择框架,并打开可视化构建器,在生成代码前完成所有自定义配置。这种方式与传统的脚手架工具(如 create-next-appcreate-vite)形成对比——后者通常需要在项目初始化后再添加样式和组件库。通过将这些决策前置,可视化构建器省去了开发者以往需要手动完成的重复性配置工作。当开发者对自定义配置满意后,系统会生成一条包含所有所选参数的定制化 shadcn create 命令。

这款可视化构建器是 shadcn 生态中最重要的新增功能之一,拥有完善的设计系统配置与组件级预览能力,为创建和生成完整的 shadcn 应用提供了全新方式——在编写代码前就能确定所有设计方案。

对于熟悉此前 init 工作流的开发者,安装文档已确认将 shadcn create 作为推荐的新项目创建起点,不过传统的 npx shadcn@latest init 命令仍然可用于向现有项目添加 shadcn。

可视化构建器的理念与 shadcn 的核心原则——开放代码所有权——高度一致。与以 npm 包形式发行的组件库不同,shadcn 的组件是直接复制到项目代码库中的,这让开发者拥有完全的控制权。这种做法在 Reddit 上引发了社区讨论,有用户对 shadcn 的流行表示不解,其中一位用户总结了原因:

Shadcn 组件是即插即用的,你可以根据自身需求随意定制。举个例子——我们遇到过组合框过滤功能的问题,我直接禁用了内置过滤,换成了另一个库。

另一个好处是,当部分功能无法正常使用时,社区会提供替代方案或组件,这要得益于它极高的人气。

在 Twitter 上,作者发布的公告推文获得了巨大反响,收获超过 9000 个点赞和 400 多条评论。

Shadcn 是由 Vercel 的 shadcn 打造的开源组件分发平台。与传统组件库不同,它以代码注册表的形式运作,组件直接安装到项目中,而非作为依赖项引入。该平台在 GitHub 上已获得超过 10 万星标,支持 Next.js、React、Vue 和 Svelte 等多个框架。

原文链接:

https://www.infoq.com/news/2026/02/shadcn-ui-builder/