首页
关于道锋
友情链接
公告栏
麟图图床
麟云文件
麟云证书
BH5UVN
Search
1
使用ReDroid打造自己的云手机
5,206 阅读
2
Cloudflare SAAS 接入自选教程
2,807 阅读
3
CloudFront CDN配置教程
2,446 阅读
4
Frpc使用XTCP不通过服务器传输
2,235 阅读
5
兽装曲腿制作文档
2,209 阅读
默认
科学
热力学
Furry
小说
星河野望
手工制作
道具制作
音影
图像工具
计算机
渗透
硬件
编程
网络
记录
AI人工智能
CVE
软件工具
装机教程
C/C++
C#
Go
HTML5+JS+CSS
JAVA
Lua
Rust
PHP
Python2/3
Nodejs
编译
C/C++学习日志
Golang学习日志
Rust开发技巧
Rust学习日志
Rust开发教程
Nonebot2机器人框架
python开发教程
python开发技巧
Python学习日志
ai绘画
电子电路
电路设计
PCB打板
制作实战
无线电
摄影
运维
WEB
KVM云计算
docker
Ansible
代码管理
Kubernetes
Linux
MySQL
shell
集群
Zabbix
Prometheus
数据安全
Redis
istio
ELK
Nginx
Apache
Tomcat
Elasticsearch
Logstash
Kibana
测评
服务器
登录
Search
标签搜索
开源
源码
教程
服务器
环境搭建
摄影
rustlang
Rust
VS CODE
v2ray
bbr
加速
网络优化
拥塞控制
CloudFront教程
CF教程
AWS教程
CloudFront接入
Frpc
Frps
道锋潜鳞
累计撰写
447
篇文章
累计收到
129
条评论
首页
栏目
默认
科学
热力学
Furry
小说
星河野望
手工制作
道具制作
音影
图像工具
计算机
渗透
硬件
编程
网络
记录
AI人工智能
CVE
软件工具
装机教程
C/C++
C#
Go
HTML5+JS+CSS
JAVA
Lua
Rust
PHP
Python2/3
Nodejs
编译
C/C++学习日志
Golang学习日志
Rust开发技巧
Rust学习日志
Rust开发教程
Nonebot2机器人框架
python开发教程
python开发技巧
Python学习日志
ai绘画
电子电路
电路设计
PCB打板
制作实战
无线电
摄影
运维
WEB
KVM云计算
docker
Ansible
代码管理
Kubernetes
Linux
MySQL
shell
集群
Zabbix
Prometheus
数据安全
Redis
istio
ELK
Nginx
Apache
Tomcat
Elasticsearch
Logstash
Kibana
测评
服务器
页面
关于道锋
友情链接
公告栏
友人
iMin博客
特资啦!个人资源分享站
三石的记录
咬一口激动的鱼
中二病晚期の物語
奇梦博客
布丁の小窝
道麟笔记
迷失的小K
koto's Site
西西のBlog
锐冰龙小站
Nick的琐碎日常
渣渣120
猎空のBlog“
Suntの小破站
BG5VXJ-无线电
Abyss博客
麟图图床
麟云文件
麟云证书
BH5UVN
搜索到
48
篇与
的结果
2025-07-11
DNS压力测试工具的Go实现
DNS压力测试工具的Go实现:高并发网络编程实战最近开发了一个DNS压力测试工具,主要用于测试DNS服务器的性能和稳定性。这个项目使用Go语言实现,充分利用了Go的并发特性来模拟大量DNS查询请求。项目已经开源在GitHub,这篇文章详细分析一下其中的技术实现和设计思路。DNS协议基础和数据包结构在深入代码分析之前,先了解一下DNS协议的基本结构和工作原理,这对理解后续的实现细节至关重要。DNS消息格式详解DNS协议基于UDP传输(标准情况下),每个DNS消息都有固定的结构格式。一个标准的DNS查询包含以下几个部分:DNS Header (12 bytes) +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | ID | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ |QR| Opcode |AA|TC|RD|RA| Z | RCODE | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | QDCOUNT | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | ANCOUNT | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | NSCOUNT | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | ARCOUNT | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+Header字段解析:ID (16位):查询标识符,用于匹配查询和响应QR (1位):查询/响应标志,0表示查询,1表示响应Opcode (4位):操作码,0表示标准查询RD (1位):期望递归查询标志QDCOUNT (16位):问题部分的条目数ANCOUNT (16位):回答部分的条目数DNS查询段(Question Section)Header之后是查询段,包含要查询的域名和查询类型:Question Section +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ / QNAME / +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | QTYPE | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | QCLASS | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+QNAME编码:域名使用特殊的编码格式,比如www.example.com会被编码为:3www7example3com0每个标签前面是长度字节,整个域名以0字节结尾。QTYPE常见值:A记录 (1):IPv4地址NS记录 (2):权威名称服务器MX记录 (15):邮件交换记录AAAA记录 (28):IPv6地址TXT记录 (16):文本记录QCLASS:通常为1,表示Internet类别。DNS包大小和传输特性UDP限制:传统DNS over UDP的包大小限制为512字节。如果响应超过这个大小,服务器会设置TC(截断)标志,客户端需要使用TCP重新查询。EDNS扩展:现代DNS实现支持EDNS(0)扩展,允许更大的UDP包(通常4096字节),同时提供额外的功能标志。查询特征:DNS查询通常很小(50-100字节)响应大小变化很大(从几十字节到几KB)查询具有突发性特征大部分查询会被缓存,减少上游服务器负载真实网络中的DNS行为模式理解真实DNS流量的特征对于设计压力测试工具很重要:查询分布特征:80%的查询集中在少数热门域名20%的查询是长尾域名或随机查询恶意查询通常具有高随机性特征时间特征:查询具有明显的时间周期性工作时间查询量显著高于夜间突发事件会导致特定域名查询激增地理特征:本地DNS服务器承载大部分查询跨地区查询延迟明显更高CDN和缓存系统影响查询分布miekg/dns库的设计理念在我们的代码中使用的github.com/miekg/dns库是Go语言中最专业的DNS处理库,它的设计有几个重要特点:完整的RFC兼容性:库实现了DNS相关的所有主要RFC标准,包括基础的RFC 1035、EDNS的RFC 2671、安全扩展DNSSEC等。类型安全的API:msg := new(dns.Msg) msg.SetQuestion(dns.Fqdn(domain), dns.TypeA)通过类型安全的API,避免了手动构建DNS包可能出现的格式错误。性能优化:库内部使用了高效的字节操作和内存管理,避免了不必要的内存分配和拷贝。扩展性支持:支持现代DNS特性如EDNS、DNSSEC、DNS over HTTPS等。了解了这些DNS协议的基础知识后,我们再来看代码实现就更容易理解每个部分的设计考虑了。项目背景和应用场景DNS压力测试在网络基础设施维护中是一个重要的环节。无论是评估DNS服务器的承载能力,还是测试网络防护设备的过滤效果,都需要能够生成大量真实的DNS查询流量。传统的压力测试工具往往功能复杂,配置繁琐,而这个工具专注于DNS查询的核心功能,提供了简洁高效的解决方案。这个工具的主要应用场景包括:DNS服务器性能测试、网络设备压力测试、DNS缓存系统验证、网络安全设备测试等。通过模拟真实的DNS查询流量,可以有效评估目标系统在高负载情况下的表现。架构设计思路整个工具的架构设计遵循了"简单而高效"的原则。核心思路是使用Go的goroutine为每个DNS服务器创建独立的查询线程,每个线程负责向特定的DNS服务器发送连续的查询请求。这种设计的优势在于:// 为每个DNS服务器启动一个goroutine for _, serverAddr := range dnsServers { wg.Add(1) go func(addr string) { defer wg.Done() sendDNSQueries(addr, *mainDomain, qType) }(serverAddr) }每个goroutine都是完全独立的,这意味着如果某个DNS服务器出现问题(比如超时或拒绝连接),不会影响其他goroutine的正常工作。同时,通过sync.WaitGroup来协调所有goroutine的生命周期,确保程序能够优雅地启动和关闭。DNS服务器选择策略工具内置了一个精心选择的DNS服务器列表,涵盖了全球主要的公共DNS服务提供商:dnsServers := []string{ "8.8.8.8:53", // Google DNS "8.8.4.4:53", // Google DNS Secondary "1.1.1.1:53", // Cloudflare DNS "1.0.0.1:53", // Cloudflare DNS Secondary "223.6.6.6:53", // 阿里DNS "223.5.5.5:53", // 阿里DNS Secondary "114.114.114.114:53", // 114DNS "114.114.115.115:53", // 114DNS Secondary // ... 更多服务器 }这个列表的设计考虑了几个因素:地理分布覆盖全球主要区域,确保测试的代表性;服务质量这些都是知名的、稳定的DNS服务提供商;负载分散通过向多个服务器发送请求,避免对单一服务器造成过大压力。这种多目标策略的好处是可以同时测试不同地理位置、不同服务商的DNS服务器性能,获得更全面的测试数据。随机子域名生成算法为了模拟真实的DNS查询场景,工具实现了一个智能的随机子域名生成算法。这个算法的核心思想是生成具有真实域名特征的随机字符串:func generateRandomSubdomain(domain string) string { // 生成2-15级长度的子域名 levels := rand.Intn(14) + 2 // 生成2-15之间的随机数 subdomain := "" for i := 0; i < levels; i++ { subdomain += generateRandomString(rand.Intn(10)+1) + "." } return subdomain + domain }这个算法有几个关键的设计决策:层级数量的随机化:真实的域名结构复杂多样,从简单的二级域名到复杂的多级子域名都存在。通过随机生成2-15层的子域名,可以更好地模拟真实网络环境中的查询模式。字符集的选择:const charset = "123456789abcdefghijklmnopqrstuvwxyz"字符集排除了数字0和字母o,这是一个很细致的考虑。在真实的域名中,为了避免混淆,很多域名注册商都会避免使用容易混淆的字符组合。这种设计让生成的域名更接近真实情况。长度的变化:每个域名级别的长度在1-10个字符之间随机变化,这种变化模拟了真实域名的长度分布特征。短的级别可能代表常见的前缀(如www、mail),长的级别可能代表具体的服务名称或随机标识符。网络连接管理网络连接的管理是这个工具的核心技术点。代码使用了UDP协议进行DNS查询,这是DNS协议的标准传输方式:conn, err := net.Dial("udp", serverAddr) if err != nil { fmt.Printf("Error connecting to DNS server %s: %v\n", serverAddr, err) return } defer conn.Close()使用UDP的原因有几个:性能优势:UDP是无连接协议,没有TCP的三次握手开销,适合高频率的短消息传输;DNS标准:绝大多数DNS查询都使用UDP协议,除非响应数据超过512字节才会回退到TCP;资源效率:UDP连接的系统资源消耗更小,可以支持更高的并发量。连接复用策略:每个goroutine建立一个长连接,然后复用这个连接发送所有查询。这种设计避免了频繁建立和销毁连接的开销,同时保持了代码的简洁性。DNS消息构建和序列化工具使用了第三方库github.com/miekg/dns来处理DNS协议的细节:msg := new(dns.Msg) msg.SetQuestion(dns.Fqdn(subdomain), qType) data, err := msg.Pack()这个库的使用体现了Go语言生态的优势。dns.Fqdn()函数自动处理域名的FQDN(Fully Qualified Domain Name)格式转换,确保域名以点号结尾。msg.Pack()将DNS消息结构体序列化为符合RFC标准的二进制格式。查询类型的处理:qType, ok := dns.StringToType[*queryType] if !ok { fmt.Println("Invalid query type. Please use A, MX, NS, etc.") return }通过dns.StringToType映射表,用户可以使用直观的字符串(如"A"、"MX"、"NS")来指定查询类型,工具会自动转换为对应的数值常量。这种设计大大提高了工具的易用性。并发控制和资源管理Go语言的并发模型是这个工具的核心优势。通过goroutine和channel,可以轻松实现高并发的网络操作:var wg sync.WaitGroup for _, serverAddr := range dnsServers { wg.Add(1) go func(addr string) { defer wg.Done() sendDNSQueries(addr, *mainDomain, qType) }(serverAddr) } wg.Wait()WaitGroup的使用:sync.WaitGroup提供了一种简洁的方式来等待所有goroutine完成。在这个应用中,由于每个goroutine都运行无限循环,wg.Wait()实际上会一直阻塞,直到程序被外部信号终止。goroutine的生命周期管理:每个goroutine都有明确的生命周期,从创建到销毁都有对应的资源管理。defer conn.Close()确保无论goroutine如何退出,网络连接都会被正确关闭。闭包和变量捕获:在启动goroutine时使用了闭包的技巧,通过函数参数传递serverAddr,避免了闭包捕获循环变量可能导致的问题。错误处理策略工具采用了"容错但不静默"的错误处理策略:_, err = conn.Write(data) if err != nil { //fmt.Printf("Error sending DNS query to %s: %v\n", serverAddr, err) }可以看到,发送错误的日志输出被注释掉了。这是一个有意的设计决策:在高并发的压力测试中,网络错误是很常见的(比如目标服务器过载、网络拥塞等),如果每个错误都输出日志,会产生海量的日志信息,反而影响工具的性能和可用性。但连接建立失败的错误仍然会被输出,因为这类错误通常表示配置问题或严重的网络问题,需要用户关注。性能优化考虑内存使用优化:每次查询都会创建新的DNS消息对象,这在高并发场景下可能产生大量的短生命周期对象。Go的垃圾回收器可以很好地处理这种模式,但如果需要进一步优化,可以考虑使用对象池来复用消息对象。CPU使用优化:随机字符串生成是CPU密集型操作,特别是在高频率查询的情况下。当前的实现使用了简单的循环,如果需要更高的性能,可以考虑预生成字符串池或使用更高效的随机数生成算法。网络I/O优化:当前每个UDP连接都是阻塞式的,在极高并发的场景下,可能需要考虑使用非阻塞I/O或者连接池来进一步提升性能。扩展性设计虽然当前的工具功能相对简单,但代码结构为扩展提供了良好的基础:配置参数化:通过flag包提供的命令行参数,用户可以自定义目标域名和查询类型。这种设计为添加更多配置选项(如并发数、查询频率等)提供了框架。模块化设计:子域名生成、DNS查询发送、连接管理等功能都被分离到独立的函数中,便于单独测试和修改。数据输出接口:虽然当前版本没有实现详细的统计功能,但代码结构可以很容易地添加性能监控、成功率统计、响应时间测量等功能。实际使用场景和效果这个工具在实际使用中表现出了很好的效果。在一台普通的个人电脑上,可以轻松生成每秒数千次的DNS查询,足以对大多数DNS服务器产生明显的负载压力。测试DNS服务器性能:通过观察不同DNS服务器的响应情况,可以评估其性能差异和稳定性。网络设备压力测试:可以用来测试防火墙、路由器等网络设备在高DNS查询负载下的表现。DNS缓存验证:通过查询大量不存在的域名,可以测试DNS缓存系统的行为和性能。安全和合规考虑需要特别强调的是,这个工具的设计初衷是用于合法的测试和研究目的。在使用时必须遵守相关的法律法规和服务条款:合理使用:避免对公共DNS服务器造成过度负载,建议在自己的测试环境中使用。监控和控制:建议添加查询频率限制和总查询数量控制,避免无节制的压力测试。透明性:在企业环境中使用时,应该确保相关人员知晓测试活动,避免被误认为是恶意攻击。技术栈总结这个项目充分展示了Go语言在网络编程中的优势:并发模型:goroutine和channel让高并发网络编程变得简单直观。标准库:丰富的网络和系统调用支持,减少了对第三方依赖的需求。生态系统:优秀的第三方库(如miekg/dns)提供了专业的协议支持。部署简便:编译后的单一可执行文件,无需复杂的部署环境。总结这个DNS压力测试工具虽然代码量不大,但涵盖了网络编程、并发控制、协议处理、随机算法等多个技术领域。通过精心的设计,用不到200行的代码实现了一个功能完整、性能优秀的专业工具。从开发的角度来看,这个项目是学习Go语言网络编程和并发编程的一个很好的案例。它展示了如何用简洁的代码实现复杂的功能,以及如何在性能和可维护性之间找到平衡。完整的源代码和使用说明可以在GitHub仓库中找到。如果你对网络编程或DNS技术感兴趣,这个项目提供了一个很好的学习和实验平台。欢迎fork和提交issue,一起完善这个工具。
2025年07月11日
16 阅读
0 评论
1 点赞
2025-07-11
双眼动画路径生成:从物理模拟到串口通信的完整解决方案
双眼动画系统的实现:从物理模拟到串口通信的完整解决方案最近在做一个机器人眼睛动画项目,需要实现逼真的眼球运动和眨眼效果。经过一段时间的开发,完成了一个基于多线程的眼睛动画系统,支持实时的眼球运动模拟、自然的眨眼动画,以及通过串口与硬件设备进行通信。项目代码已经开源在 GitHub,这篇文章详细分析一下其中的技术实现。系统架构设计整个系统采用了三线程架构:一个动画更新线程负责核心的眼球运动和眨眼逻辑计算,两个输出线程分别处理左右眼的数据发送。这种设计的好处是将计算逻辑和I/O操作解耦,确保动画计算的稳定性不受串口通信延迟的影响。// 系统核心结构 typedef struct { float eyeOldX, eyeOldY; // 当前位置 float eyeNewX, eyeNewY; // 目标位置 bool inMotion; // 运动状态 uint32_t moveStartTimeMs; // 运动开始时间 uint32_t moveDurationMs; // 运动持续时间 BlinkState blinkState; // 眨眼状态 float eyeOpenness; // 眼睛开合度 } EyeState;使用了一个共享的EyeState结构体来维护眼睛的完整状态,通过std::mutex保护多线程访问,确保数据一致性。眼球运动算法实现眼球运动的核心思路是模拟人类眼球的真实运动模式:大幅度的跳跃式移动(扫视)和小幅度的微调(微眼跳)。算法设计了一个状态机来控制这两种运动模式的切换。路径生成的数学基础在深入具体算法之前,先要理解整个坐标系统的设计。系统使用了一个以MAP_RADIUS为半径的圆形映射区域,其中MAP_RADIUS = 240像素。这个设计的巧妙之处在于:#define SCREEN_WIDTH 240 #define SCREEN_HEIGHT 240 #define MAP_RADIUS 240实际的可视区域被限制在一个更小的圆形范围内,计算公式为:float effective_radius = (MAP_RADIUS * 2 - SCREEN_WIDTH * M_PI_2) * scale_factor;这里的M_PI_2(π/2)是一个关键的修正因子,它考虑了从方形屏幕到圆形映射的几何变换。通过这种方式,我们可以确保生成的所有眼球位置都在有效的显示范围内,避免眼球"跑出屏幕"的情况。扫视运动(Saccadic Movement)的路径生成扫视是眼球的主要运动模式,特点是快速、大幅度的跳跃。路径生成算法采用了极坐标到直角坐标的转换方法,但用了一种更高效的实现:// 扫视运动的有效半径计算 float r = (MAP_RADIUS * 2 - SCREEN_WIDTH * M_PI_2) * 0.75f; // 首先在X轴上随机选择位置 float relativeX = random_float(-r, r); // 根据圆的方程计算Y轴的最大范围 float maxY = sqrtf(r * r - relativeX * relativeX); float relativeY = random_float(-maxY, maxY); // 转换为绝对坐标 state->eyeNewX = MAP_RADIUS + relativeX; state->eyeNewY = MAP_RADIUS + relativeY;这个算法的核心是圆的方程:x² + y² = r²。给定X坐标后,Y坐标的取值范围就确定了:y = ±√(r² - x²)。这种方法比传统的极坐标转换(x = r*cos(θ), y = r*sin(θ))更高效,因为避免了三角函数的计算。扫视运动的scale_factor = 0.75f意味着眼球的扫视范围被限制在理论最大范围的75%内,这样可以留出一些边界缓冲,让运动看起来更自然。运动持续时间设置为83-166毫秒,这个数值是基于人眼扫视的生理特性确定的:人类的快速扫视通常在50-200毫秒之间完成。微眼跳(Microsaccade)的增量路径算法微眼跳采用了完全不同的路径生成策略——增量式生成。与扫视的绝对位置生成不同,微眼跳是基于当前位置的相对偏移:// 微眼跳的范围计算(约为扫视范围的1/10) float r = (MAP_RADIUS * 2 - SCREEN_WIDTH * M_PI_2) * 0.07f; // 生成相对于当前位置的偏移量 float dx = random_float(-r, r); float h = sqrtf(r * r - dx * dx); float dy = random_float(-h, h); // 应用偏移到当前位置 state->eyeNewX = state->eyeOldX + dx; state->eyeNewY = state->eyeOldY + dy;这种设计的优势是微眼跳不会让眼球产生大幅度的"跳跃感",而是在当前注视点附近进行微小的调整。0.07的缩放因子意味着微眼跳的范围约为扫视范围的1/10,持续时间也更短(7-25毫秒),这完全符合人眼微眼跳的生理特征。运动状态机的路径决策逻辑路径生成的决策逻辑通过一个复杂的状态机实现,它需要在扫视和微眼跳之间做出智能选择:if ((t - state->lastSaccadeStopMs) > state->saccadeIntervalMs) { // 执行扫视运动 // ... 扫视路径生成代码 state->moveDurationMs = random_range(83, 166); state->saccadeIntervalMs = 0; // 标记需要重新计算下次扫视间隔 } else { // 执行微眼跳 // ... 微眼跳路径生成代码 state->moveDurationMs = random_range(7, 25); }这里的关键是saccadeIntervalMs的动态计算。每次扫视结束后,系统会根据当前的凝视缩放因子重新计算下次扫视的间隔时间:uint32_t scaledMaxGazeMs = static_cast<uint32_t>(maxGazeMs * gazeScaleFactor); state->saccadeIntervalMs = random_range(state->moveDurationMs, scaledMaxGazeMs);这种设计让眼球的运动模式更加自然:在大部分时间里进行微小的微眼跳调整,偶尔进行大幅度的扫视运动。运动插值的数学模型为了让眼球运动更加平滑,系统使用了一个特殊的缓动函数进行路径插值:float e = (float)dt / (float)scaledDurationMs; // 线性进度 [0, 1] float e2 = e * e; // e的平方 e = e2 * (3.0f - 2.0f * e); // 平滑步函数: 3e² - 2e³这个函数被称为"平滑步函数"(smoothstep),它的数学表达式是f(t) = 3t² - 2t³。这个函数有几个重要特性:f(0) = 0, f(1) = 1:确保插值在正确的边界f'(0) = 0, f'(1) = 0:保证运动开始和结束时速度为零中间段的导数为正:确保单调递增相比线性插值,这种缓动函数让眼球运动具有"加速-匀速-减速"的特征,更符合人眼的运动模式。边界检测和约束处理虽然路径生成算法理论上会保证所有点都在有效范围内,但在实际实现中,还是需要考虑边界情况的处理。特别是在微眼跳的增量计算中,当前位置靠近边界时,简单的偏移可能会导致越界。代码中通过预先计算有效半径的方式来避免这个问题,但在更复杂的应用场景中,可能需要额外的边界检测和坐标钳制逻辑:// 理论上需要的边界检测(当前代码中通过预计算避免了这个问题) float clamp_to_circle(float x, float y, float center_x, float center_y, float radius) { float dx = x - center_x; float dy = y - center_y; float distance = sqrtf(dx*dx + dy*dy); if (distance > radius) { float scale = radius / distance; return {center_x + dx*scale, center_y + dy*scale}; } return {x, y}; }参数化控制对路径生成的影响用户可调节的参数对路径生成有直接影响:凝视缩放因子(gazeScaleFactor):影响扫视的触发频率,值越大,扫视间隔越长移动速度因子(moveSpeedFactor):通过除法运算延长运动持续时间,从而减慢运动速度// 速度控制的实现 uint32_t scaledDurationMs = static_cast<uint32_t>(state->moveDurationMs / moveSpeedFactor);这种参数化设计让同一套路径生成算法可以适应不同的应用需求,从慢速的冥想状态到快速的警觉状态都能很好地模拟。眨眼动画系统眨眼动画采用了状态机模式,包含三个状态:未眨眼、闭合中、打开中。这种设计可以精确控制眨眼的每个阶段,实现更自然的效果。typedef enum { NOT_BLINKING = 0, BLINK_CLOSING = 1, BLINK_OPENING = 2 } BlinkState;眨眼的触发机制采用了随机间隔,基础间隔为2-6秒,这个数值参考了人类的平均眨眼频率。眨眼动作的持续时间分为两个阶段:闭合阶段50-100毫秒,打开阶段是闭合阶段的2倍,这样可以模拟真实眨眼的不对称特性。参数化控制系统为了让系统更加灵活,设计了一套完整的参数化控制系统。用户可以通过命令行参数调整各种行为:--gazescale: 控制凝视时间,值越大眼睛移动频率越低--movespeed: 控制眼球移动速度,值越小移动越慢--blinkfreq: 控制眨眼频率,值越小眨眼越少--blinkspeed: 控制眨眼速度,值越小眨眼动作越慢这些参数通过乘法因子的方式应用到相应的计算中,比如移动速度的控制:uint32_t scaledDurationMs = static_cast<uint32_t>(state->moveDurationMs / moveSpeedFactor);串口通信协议系统使用JSON格式进行数据传输,这样既保证了数据的结构化,又具有很好的可读性和扩展性。数据包格式如下:{ "req": "c", "d": { "x": 0.25, "y": -0.33, "l": 0.95 } }其中req字段表示请求类型,d字段包含实际的眼睛数据。坐标系统使用了归一化的浮点数,范围从-1.0到1.0,中心点为(0,0)。这种设计的好处是与具体的硬件分辨率无关,接收端可以根据自己的需要进行缩放。串口配置采用了115200波特率,8位数据位,无校验位,1个停止位。为了提高通信的可靠性,在串口初始化时禁用了各种流控制和特殊字符处理:tty.c_cflag &= ~CRTSCTS; // 禁用硬件流控制 tty.c_iflag &= ~(IXON | IXOFF | IXANY); // 禁用软件流控制 tty.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); // 禁用规范模式时间管理和同步系统使用了clock_gettime(CLOCK_MONOTONIC)来获取高精度的时间戳,这比gettimeofday()更适合做时间间隔计算,因为它不受系统时间调整的影响。帧率控制采用了固定时间步长的方式,设定为40fps(25ms每帧)。这个频率对于眼球动画来说已经足够流畅,同时也不会给系统带来过大的负担:#define FPS 40 #define FRAME_DURATION_MS (1000 / FPS) uint32_t frameDuration = get_time_ms() - frameStart; if (frameDuration < FRAME_DURATION_MS) { delay_ms(FRAME_DURATION_MS - frameDuration); }错误处理和容错机制在串口通信方面,实现了比较完善的错误处理机制。当写入失败时,系统会尝试重新建立连接,这对于长时间运行的设备来说非常重要:if (bytes_written < 0) { close(fd); fd = setup_serial_port(port_name, BAUD_RATE); if (fd < 0) { std::cerr << eye_name << "重新连接串口失败,线程退出" << std::endl; break; } }同时,系统还实现了优雅的退出机制,通过信号处理函数捕获Ctrl+C和SIGTERM信号,确保所有线程能够正常退出并释放资源。性能优化考虑在多线程设计中,为了减少锁竞争,动画更新线程和数据发送线程的工作频率是一致的,都是40fps。数据发送线程每次都会完整复制一份眼睛状态,这样可以最小化临界区的大小。另外,所有的浮点数计算都使用了单精度float,这在保证精度的同时也提供了更好的性能。对于眼球动画这样的应用场景,单精度的精度已经完全足够。扩展性设计系统的设计考虑了很好的扩展性。比如左右眼交换功能的实现,通过一个简单的布尔值就可以改变数据的发送目标,这对于一些特殊的硬件配置很有用。数据格式的设计也很灵活,JSON格式可以很容易地添加新的字段,比如瞳孔大小、眼睛颜色等。坐标系统的归一化设计也使得系统可以适应不同分辨率的显示设备。总结这个眼睛动画系统在技术上实现了几个关键点:基于生理学原理的运动模型、稳定的多线程架构、灵活的参数化控制、可靠的串口通信。整个系统的代码结构清晰,模块化程度高,既可以作为独立的眼睛动画服务使用,也可以很容易地集成到其他机器人项目中。从开发的角度来看,这个项目涉及了实时系统设计、数值计算、串口通信、多线程编程等多个技术领域,是一个很好的综合性项目。如果你对机器人动画或者实时系统开发感兴趣,可以从这个项目中学到不少东西。完整的源代码和详细的使用说明都可以在 GitHub仓库 中找到,欢迎大家fork和提issue讨论。
2025年07月11日
17 阅读
0 评论
0 点赞
2024-12-15
在Ubuntu 24.10下将ONNX模型转换RKNN
文章介绍了 RKNPU 和 RKNN-Toolkit2 的基础知识,详细说明了如何在 Ubuntu 系统上安装工具链,并结合案例展示了如何将模型从 ONNX 转换为 RKNN 格式并部署在 Luckfox Pico 开发板上。
2024年12月15日
759 阅读
0 评论
0 点赞
2024-08-25
新版ubuntu使用pip时发生的错误
新版ubuntu使用pip时发生错误:error: externally-managed-environment × This environment is externally managed ╰─> To install Python packages system-wide, try apt install python3-xyz, where xyz is the package you are trying to install. If you wish to install a non-Debian-packaged Python package, create a virtual environment using python3 -m venv path/to/venv. Then use path/to/venv/bin/python and path/to/venv/bin/pip. Make sure you have python3-full installed. If you wish to install a non-Debian packaged Python application, it may be easiest to use pipx install xyz, which will manage a virtual environment for you. Make sure you have pipx installed. See /usr/share/doc/python3.11/README.venv for more information. note: If you believe this is a mistake, please contact your Python installation or OS distribution provider. You can override this, at the risk of breaking your Python installation or OS, by passing --break-system-packages. hint: See PEP 668 for the detailed specification.收到一个错误提示: error: externally-managed-environment ,即“外部管理环境”错误,但这不是一个 bug,新的发行版中,正在使用 Python 包来实现此增强功能,这个更新是为了避免操作系统包管理器 (如pacman、yum、apt) 和 pip 等特定于 Python 的包管理工具之间的冲突,这些冲突包括 Python 级 API 不兼容和文件所有权冲突。可以看一下python官方的说明:PEP 668 – Python base environments Python 增强提案 (PEP) 解决方案:1:如果你习惯于原来的用法可以强制删除此警告:sudo mv /usr/lib/python3.x/EXTERNALLY-MANAGED /usr/lib/python3.x/EXTERNALLY-MANAGED.bk注意python版本号写你自己的别直接抄,不知道到底是多少可以进/user/lib看看:find /usr/lib/ -type d -name "*python*"2:老实点使用pipx安装pipx:sudo apt install pipx以后就使用Pipx去安装包文件了:pipx install package_name添加环境变量:pipx ensurepath删除使用pipx安装的软件包:pipx uninstall package_name3:使用venv如果你是专业开发人员,在运行或构建py文件时遇到“ModuleNotFoundError: No module named 'xxx'”错误,推荐使用Python虚拟环境,借助虚拟环境,使用不同版本的包依赖项和Python,避免包之间的任何冲突。安装 venv:sudo apt install python3-venv #或者 sudo apt install python3.10-venv生成Python虚拟环境:mkdir -p $HOME/.env && python3 -m venv $HOME/.env/project_name将看到一个.env在主目录中,并且你将在 .env 中拥有项目目录,每个虚拟环境项目目录中都会有自己的 Python 和 Pip 副本。安装模块:$HOME/.env/project_name/bin/python -m pip install --upgrade pip $HOME/.env/project_name/bin/python -m pip install package_name用新的虚拟环境执行py文件:source $HOME/.env/project_name/bin/activate $HOME/.env/project_name/bin/python ./xxxx.py
2024年08月25日
108 阅读
0 评论
0 点赞
2024-01-13
使用ReDroid打造自己的云手机
前言市面上已经存在很多云手机厂商如红手指、多多云、雷电云、河马云手机等,价格从几十到上百元每月一台。价格还好说,但设备运行稳定性、可靠性、数据安全性全部依赖第三方厂商,注定不能进行敏感性操作或部署对安全可靠高要求的企业级服务。本文介绍一种开源的 AIC (Android In Container) 解决方案 ReDroid,使用本教程可以在一台普通型服务器运行多个安卓设备环境,并可在客户机电脑连接使用该云手机。Redroid介绍redroid(Remote an Droid)是一个 GPU 加速的 AIC(Android In Cloud)解决方案。Docker您可以在 Linux 主机( 、podman等)中启动多个实例k8s。redroid支持arm64和amd64架构。 redroid适用于云游戏、虚拟化电话、自动化测试等。目前支持:安卓 14 ( redroid/redroid:14.0.0-latest)仅适用于 Android 14 64 位 ( redroid/redroid:14.0.0_64only-latest)安卓 13 ( redroid/redroid:13.0.0-latest)仅适用于 Android 13 64 位 ( redroid/redroid:13.0.0_64only-latest)安卓 12 ( redroid/redroid:12.0.0-latest)仅适用于 Android 12 64 位 ( redroid/redroid:12.0.0_64only-latest)安卓 11 ( redroid/redroid:11.0.0-latest)安卓 10 ( redroid/redroid:10.0.0-latest)安卓 9 ( redroid/redroid:9.0.0-latest)安卓 8.1 ( redroid/redroid:8.1.0-latest)入门redroid 应该能够在任何 Linux 上运行(启用一些内核功能)。这里以使用阿里云的X86服务器进行演示,具体如下:配置:vCPUs2内存2G储存40G系统ubuntu-22.04架构x86-64带宽3M安装Docker## 安装 docker https://docs.docker.com/engine/install/#server # 根据 Docker 官方文档安装Docker curl -fsSL https://get.docker.com -o get-docker.sh sudo sh get-docker.sh #或者从仓库下载 sudo apt update sudo apt-get install -y docker.io systemctl start docker systemctl enable docker 安装内核扩展模块更具不同的系统,有不一样的安装方法,具体如下 # 拉取内核模块源码 git clone https://github.com/remote-android/redroid-modules cd ./redroid-modules # Ubuntu 16.04 / 18.04 / 20.04 sudo apt-get install -y git kmod make gcc linux-headers-`uname -r` sudo make # build kernel modules sudo make install # build and install *unsigned* kernel modules # Ubuntu 20.04+ (kernel 5.0+) sudo modprobe ashmem_linux sudo modprobe binder_linux devices=binder,hwbinder,vndbinder # AmazonLinux2 git checkout origin/amazonlinux2 sudo yum install git kmod make "kernel-devel-uname-r == `uname -r`" sudo make # build kernel modules sudo make install # build and install *unsigned* kernel modules # Alibaba Cloud Linux 2 git checkout origin/alibabalinux2 sudo yum install git kmod make "kernel-devel-uname-r == `uname -r`" sudo make # build kernel modules sudo make install # build and install *unsigned* kernel modules # Alibaba Cloud Linux 3 git checkout origin/alibabalinux3 sudo yum install git kmod make "kernel-devel-uname-r == `uname -r`" sudo make # build kernel modules sudo make install # build and install *unsigned* kernel modules # openEuler 20.03 / kernel 4.19 git checkout origin/openeuler2003 sudo yum install gcc kernel-devel sudo KDIR=/usr/src/kernels/<VER> make install # 检查模块状态 lsmod | grep -e ashmem_linux -e binder_linux # example output: # binder_linux 147456 79 # ashmem_linux 16384 23 # 也可以这样验证 grep binder /proc/filesystems # output should like: nodev binder grep ashmem /proc/misc # output should like: 56 ashmem我这边因为是ubuntu 22.04,便使用 modprobe 安装如果不想换系统,可以尝试升级内核到5.0以上,默认就自带相关模块了启动容器创建Docker-compose文件docker-compose.ymlversion: "3" services: redroid: image: redroid/redroid:11.0.0-latest stdin_open: true tty: true privileged: true ports: - "20055:5555" volumes: # 資料存放在目前目錄下 - ./redroid-11-data:/data command: # 設定libndk相關 - ro.product.cpu.abilist0=x86_64,arm64-v8a,x86,armeabi-v7a,armeabi - ro.product.cpu.abilist64=x86_64,arm64-v8a - ro.product.cpu.abilist32=x86,armeabi-v7a,armeabi - ro.dalvik.vm.isa.arm=x86 - ro.dalvik.vm.isa.arm64=x86_64 - ro.enable.native.bridge.exec=1 - ro.dalvik.vm.native.bridge=libndk_translation.so - ro.ndk_translation.version=0.2.2 - ro.secure=0 cap_add: - CAP_SYS_MODULE 启动容器#确保安装了docker-compose apt install docker-compose # 进入储存docker-compose.yml的目录 cd /data/redroid-1 docker-compose up -d如果使用 22.04可能出现如下异常解决方案pip install 'urllib3<2'链接根据 Scrcpy 官方文档下载安卓投屏软件源码包到客户机,解压使用adb connect ip:5555 # adb devices 可查看连接设备列表 scrcpy --serial ip:5555高级一些额外参数样例docker run -itd --rm --privileged \ --pull always \ -v ~/data:/data \ --cap-add CAP_SYS_MODULE \ -p 5555:5555 \ redroid/redroid:11.0.0-latest \ androidboot.redroid_width=1080 \ androidboot.redroid_height=1920 \ androidboot.redroid_dpi=480 \参数描述默认androidboot.redroid_width显示宽度720androidboot.redroid_height显示高度1280androidboot.redroid_fps显示 FPS30(启用 GPU) 15(未启用 GPU)androidboot.redroid_dpi显示 DPI320androidboot.use_memfd使用 memfd 替换已弃用的 ashmem计划默认启用假androidboot.use_redroid_overlayfs使用overlayfs共享data分区/data-base:共享data分区/data-diff:私有数据0androidboot.redroid_net_ndnsDNS 服务器数量,如果未指定 DNS 服务器,将使用“8.8.8.8”0androidboot.redroid_net_dns<1..N>域名解析 androidboot.redroid_net_proxy_type代理类型;从以下选项中选择:“静态”、“pac”、“无”、“未分配” androidboot.redroid_net_proxy_host androidboot.redroid_net_proxy_port 3128androidboot.redroid_net_proxy_exclude_list逗号分隔列表 androidboot.redroid_net_proxy_pac androidboot.redroid_gpu_mode从以下选项中选择:auto、host、guest;guest:使用软件渲染;host:使用 GPU 加速渲染;auto:自动检测自动androidboot.redroid_gpu_node 自动检测ro.xxxDEBUG 目的,允许覆盖 ro.xxx 属性;例如设置ro.secure=0,则默认提供root adb shell
2024年01月13日
5,206 阅读
2 评论
3 点赞
2023-08-11
D-Link Go-RT-AC750命令注入漏洞复现
D-Link Go-RT-AC750命令注入漏洞复现
2023年08月11日
360 阅读
0 评论
0 点赞
2023-07-21
shell脚本案例-Python安装脚本
shell脚本案例-Python安装脚本
2023年07月21日
107 阅读
0 评论
0 点赞
2023-07-20
使用nginx发布tomcat站点
使用nginx发布tomcat站点
2023年07月20日
33 阅读
0 评论
0 点赞
2023-07-17
使用CloudFlare Worker搭建Vless服务,实现无服务器代理
使用CloudFlare Worker搭建Vless服务,实现无服务器代理
2023年07月17日
1,026 阅读
0 评论
2 点赞
2023-06-28
关于CRITICAL:yum.cli的一个解决方法记录
关于CRITICAL:yum.cli:Config error: Error accessing file for config file:///etc/yum.conf /usr/lib64/python2.7/site-packages/pycurl.so: undefined symbol: CRYPTO_num_locks 的解决记录
2023年06月28日
529 阅读
2 评论
2 点赞
2023-04-23
[Typecho漏洞]Typecho博客程序v1.2.1-rc仍然存在XSS漏洞
前几天,Typecho博客程序被曝出评论网址处存在存储型XSS漏洞,不少人已经被攻击,目前Typecho暂未发布修复该漏洞的教程,但是Typecho的Github仓库的最新代码已修复该漏洞,并预发布了Typecho 1.2.1-rc版本。
2023年04月23日
525 阅读
4 评论
2 点赞
2023-04-01
[Typecho漏洞]Typecho博客程序评论网址处存在存储型XSS漏洞
前几天,Typecho博客程序被曝出评论网址处存在存储型XSS漏洞,不少人已经被攻击,目前Typecho暂未发布修复该漏洞的教程,但是Typecho的Github仓库的最新代码已修复该漏洞,并预发布了Typecho 1.2.1-rc版本。
2023年04月01日
233 阅读
3 评论
2 点赞
1
2
...
4