【编程实践】黑框框里的打字小游戏,但是汇编语言
开始:
在学习王爽的《汇编语言》的过程中,我就真切地体会到编程实践对于理解的帮助。起初我没有安装书中的实验环境,看到100页左右就开始感觉无趣、吃力,看了后面忘前面,差点就要放弃这本书的学习。好在我后来还是装好了环境,这才开始在实际的编程练习中感受到一些乐趣。
学习完《汇编语言》一书后,我又开始阅读朋友给我推荐的《x86汇编语言 从实模式到保护模式》。没错,王爽书介绍的只是实模式下编程的内容。读x86一书过程中,前面接近于复习,读起来还比较轻快,但随着渐渐深入,我每次对照书阅读代码都感觉很是吃力。到了第15章“程序的动态加载和执行”时,已经常常会将保护模式和前面实模式中的内容搞混。
于是我决定自己设计并编写一个汇编程序,以进一步理顺清晰前面所学习的内容——本文便缘起于此。需要声明的一点是,我并没有打算将这个程序做成一个教程,因为那好累,我有点懒。前面一小段内容算是我的日记,后面则是笔记。
但如果真的有人对我的程序或代码感兴趣,我也在后面提供了我的代码仓库链接,欢迎大家下载我的代码。然而你想运行它确实会有点麻烦,同样的在后面我也大致介绍了程序的运行环境。
Gitee源代码仓库:清风莫追/Typing_asm (gitee.com)
文章目录
- 开始:
- 介绍
- 1 程序简述
- 2 涉及知识
- 3 运行环境
- 程序结构
- 复习知识点
- 1 常数定义
- 2 用户程序中段的重定位
- 3 关于vstart的三种情况
- 4 显存模块
- 5 命令行编译源代码
- 6 中断向量表
- 7 退出VBox对鼠标和键盘的独占
- 8 发布到Gitee
- 指令记录
- 1 伪指令
- 2 其它
- Bug记录
- 1 主引导扇区程序未成功加载用户程序
- 2 安装的int 9中断例程未正常运行
- 3 按一个键后,生成字符串的程序的不动了
- 4 按下字母变绿失效:当数据段加个字节
- 5 伪随机数循环了
- 6 数字显示不出来
- 7 环绕模块卡死
介绍
1 程序简述
如果只允许用四个字来概括我的程序,那我只能对你说:打字游戏。可很遗憾今天的我有点话痨,请允许我更详细地描述一下这个小游戏:
运行程序后,首先映入你眼帘的会是一个干净的黑框框。什么?你问我怎么不做个哪怕简单点的导引界面?其实原因你猜得到:懒。那么,接着你需要任意地按下一个键,这个程序就要正式开始了。
屏幕顶部会开始在随机的位置掉下随机的大写字母,而且总会有个字母被一圈+环绕着,不要犹豫,它就是你的目标,请按下对应的字母键吧!如果你按下了正确的字母,它就会变成绿色,同时屏幕的左下角会默默地记录着你的得分。描述到这里就结束了,毕竟它本就只是一个简单的小程序。
下面是我录制的一段程序运行时的GIF:

2 涉及知识
程序看着简单,玩起来也简单,但做起来可难了!而且最难的地方就是,我需要使用汇编语言来完成它,以至于它的源代码多达500行。关于指令的知识,我就不展开说了。除了会使用基本的指令外,想要写出本程序你还需要了解以下方面的知识:
- 显存操作。在汇编语言中,我们通过直接往显存写入数据,来让它显示我们想要的内容。与此同时你还需要了解ascii编码和字符的显示属性。
- 中断。你需要知道如何在系统中安装我们自己编写的中断例程,以及键盘扫描码相关的内容。
- 程序的加载。程序编译好后,首先是写入到磁盘里的,如何将它加载到内存中并运行?如果你是编写一个在Dos操作系统上运行的汇编程序,其实不需要这一步。但我将程序运行在一个没有操作系统的虚拟机裸机上,就需要了。
除了上面三点,我还使用“线性同余法”,用汇编实现了伪随机数的功能。不然,随机的字母、随机的下落位置,其中的随机从何而来呢?汇编并不像C语言那样有着丰富的库函数。
当然,BIOS中也是提供了一些中断例程以供用户调用的,我并不知道里面有没有随机数的功能。然而,自己尝试实现一个也挺有意思的,不是吗?这费不了多少功夫——如果你没有花很多时间调试bug的话。
3 运行环境
1、汇编语言
因为与计算机硬件实现的强相关性,汇编语言并不像其它高级语言那样标准统一。也就是说,存在多种不同的汇编语言,它们各自对应着不同的指令系统、体系结构。
好吧,其实没必要讨论那么多概念,我只是想说,本程序使用的是8086汇编语言。更进一步地说,我使用了Nasm编译器,该编译器是开源的,你可以在GitHub上找到它,而另一款大家常用的编译器是Masm。
主要是伪指令的不同会导致一些代码框架结构上的差异,如果你以前只用过Masm,可能还需要去单独了解一些Nasm的内容。
2、虚拟环境
最简单的环境搭建是使用DOSBox,它是一个包含Dos操作系统的虚拟机,可以运行8086的汇编代码。如果你打算用它的话,我的代码需要进行一些修改才能运行。
说实在用DOSBox学习汇编语言挺方便的,然而它并没有提供虚拟的磁盘,后来我安装了VisualBox和Bochs,《…从实模式式到保护模式》的书籍配套资料中有相关的安装教程(包括Nasm编译器):
http://www.lizhongc.com/
Bochs除了运行程序,还能debug;而VisualBox只能运行程序,效率要高一些。这两个虚拟机都没有操作系统,所以你要自己想办法将程序从磁盘加载到内存中来,这就是为什么前面“涉及的知识”中会说到程序的加载问题。
我的代码仓库中有两个.asm文件,其中程序typing_mbr.asm所做的事情就是把用户程序(也就是我的小游戏)加载到内存中,而typing.asm是真正的游戏程序代码。
- typing.asm
- typing_mbr.asm
Gitee源代码仓库:清风莫追/Typing_asm (gitee.com)
好吧,如果只是想用汇编语言编写并运行一个小游戏,这确实多走了不少弯路。也许我有空会尝试出个DOSBox中能跑的版本,但大概率会鸽,因为我懒。
最后还得吐槽一下,汇编语言的生产力太低了,这个小程序花了我整整16个小时。不过复习的效果感觉也不错,只是,我也不太确定是否划算。可是自己制作小作品时的那种投入感,是平常阅读(技术)书籍的过程中难以找到的。
接下来的部分是我编写代码过程中的一些笔记,就比较无聊了,Bug记录部分倒也可以参考一下。但我就不陪大家一起了,有缘再见!
程序结构
- 主引导程序:将用户从磁盘加载到内存中。
- 用户程序- 头部- 程序长度- 程序入口- 段重定位表- 代码段- 数据段
主引导程序包含信息:
- 用户程序在磁盘的位置,即起始逻辑扇区号。
- 用户程序被加载到内存的物理起始地址。
需要用到的例程:
显示:
- 显示一个字母
- 将屏幕一行内容左移一位
键盘中断:
- 获取键盘字符的扫描码
时钟中断:
- 控制字符移动速度
- 作为随机数种子(已鸽,目前采用固定种子:1)
障碍:屏幕移动与响应键盘中断是两个线程吗?
- 答:不需要,重写键盘中断即可。
复习知识点
1 常数定义
hello equ 100
定义一个值为100的常数hello,若继续mov ax,hello,则执行后ax寄存器的值为100。
在代码中引用常数或标号,都是在编译阶段发挥作用。但注意与标号使用时相区分,如果是hello db 100,然后mov ax,hello,则执行后ax的值为标号hello处的汇编地址。
2 用户程序中段的重定位
SECTION header vstart=0 ;定义用户程序头部段 program_length dd program_end ;程序总长度[0x00];用户程序入口点code_entry dw start ;偏移地址[0x04]dd section.code_1.start ;段地址[0x06] realloc_tbl_len dw (header_end-code_1_segment)/4 ;段重定位表项个数[0x0a];段重定位表 code_1_segment dd section.code_1.start ;[0x0c]code_2_segment dd section.code_2.start ;[0x10]data_1_segment dd section.data_1.start ;[0x14]data_2_segment dd section.data_2.start ;[0x18]stack_segment dd section.stack.start ;[0x1c]header_end:
如果使用主引导扇区加载用户程序,则用户程序需要描述头部信息。头部代码示例如上,记录的每个段的信息都是汇编地址,在主引导扇区程序中会转换为在物理内存中的段地址,以便之后用户程序可以通过
mov ax, [cs:data_1_segment]
mov ds, ax
这样的方式,在内存中正确地访问到对应的段。
3 关于vstart的三种情况
略了
4 显存模块
常用的是显存的文本模式,物理地址空间为0xB800~0xBFFFF。可以显示25行,每行80个字符,使用ASCII码。
5 命令行编译源代码
nasm -f bin exam.asm -o exam.bin
-f bin是要求nasm生成“纯二进制”的内容,即不包含操作系统所需要的加载和重定位信息。
6 中断向量表
对于8080PC机,中断向量表存放在0000:0000~0000:03FF的一共1024个内存单元中,每个表项占两个字,故最多可以有256个中断例程。表项中是中断处理程序的入口地址,其中高地址字存放段地址,低地址字存放偏移地址。
注:中断号从0开始。
一般0000:0200~0000:02FF这段内存是空闲的,操作系统和其他应用程序都不占用。
7 退出VBox对鼠标和键盘的独占
按右边的组合键:Alt + Ctrl(按左边的这两个键没效果)。
8 发布到Gitee
如果你使用的是vscode,且以前已经配置过与Gitee的ssh公钥连接,那么发布代码到远程Gitee仓库的步骤如下:
- vscode进入“源代码管理”栏,初始化仓库,并提交所有更改。
- 登录Gitee账号,创建一个空的仓库,并复制仓库地址。
- 在vscode中“添加远程存储库”,然后输入仓库地址以及仓库名。
- 最后,发布分支。此时点开Gitee仓库,将看到你的代码已经被上传。

指令记录
1 伪指令
section.段名称.start
获取段的汇编地址。注意与段地址的概念相区分, 段地址 ∗ 16 段地址*16 段地址∗16得到的才是段的汇编地址。
2 其它
jmp far [0x04]
从内存中取出两个字,低地址的字放入IP寄存器,高地址的字放入CS寄存器。
Bug记录
1 主引导扇区程序未成功加载用户程序
在没有操作系统的虚拟机上,目前我每次运行都会启动两个程序,一个是主引导扇区程序,它用于将用户程序从磁盘加载到内存中;另一个就是我们用来完成任务的用户程序了。
当在加载阶段就出现问题时,我习惯性地就认为是主引导程序的代码出现了问题,而实际上加载用户程序的任务是由引导程序与用户程序的头部合作完成的。
举个例子,我在用户程序的头部定义了用户程序的长度信息
;头部: 用户程序长度
program_length dd program_end ;[0x00];栈段
SECTION stack align=16 vstart=0 ;...程序结尾
program_end:
2 安装的int 9中断例程未正常运行
下面是程序的部分代码片段:
int9_new:;说明:新的int 9中断例程,在屏幕固定位置显示按下的字符push dxpush ax mov al, 'k'
SECTION data align=16 vstart=0text db 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'int9_new_store db 512 dup 0 ;存放新的int 9中断例程
程序运行后会自动逐个字符得显示text标号处的内容,我将mov al,'k'修改为mov al,'e'后,显示的内容也响应地变化,说明新的中断例程代码肯定是被成功写入到了data数据段的。

那么不能正常运行的可能原因如下:
- 中断向量表填写不正确。又分为新中断例程表项,和旧int 9中断例程的表项。
- int 9中断其实不会在按键盘时自动触发?
经过两小时的调试都没能发现问题所在,已经开始怀疑是不是VisualBox和Bochs不支持键盘中断、或者中断号并不是0x09,毕竟现在换成了虚拟的x86处理器,而不是之前看王爽书时用的8086处理器了。(期间我将王爽书的实验15代码改编后,在Bochs上也无法正常运行,暂时还不知道原因)
但搜索资料发现键盘中断的支持和中断号都应该是没有问题的:
一文讲透!Windows内核 & x86中断机制详解 - 知乎 (zhihu.com)
可后来我发现了一个现象:
代码正在Bochs运行时,我随便按下一个键,程序都会突然终止。而将新中断例程改写成以下样子后,它是可以正常运行的!按键后屏幕的左上角意料之外地正常出现了小写的字母k。
int9_new:;说明:新的int 9中断例程,在屏幕固定位置显示按下的字符push ax push esmov ax,0xb800 mov es,ax mov byte es:[0], 'k'pop espop ax iret
那么很显然,之前的问题应该来自我编写的新中断例程本身。
我之前在中断例程中使用了形如call appear_char的指令,而appear_char是我编写在用户程序中的子程序。那么问题来了,call 标号指令采用的是相对近调用,编译后指令的操作数是call指令相对于标号的偏移量。可是,中断程序中cs寄存器的值已经改变,哪里还找得到原来的子程序appear_char?只能按着原来编译出来的偏移量,跳转到一个莫名的位置罢了。
可能的解决方案:
-
将用户程序和中断例程共用的子程序,同样安装为中断例程。
-
在内存中保存用户程序的
cs段地址,中断例程中使用call far进行间接绝对远调用。问题:子程序采用
ret返回,只能实现近转移,从中断例程中调用之后就回不来了。 -
将需要用到的子程序源码复制拷贝到中断例程中。(有点无脑,但看起来很方便)
-
我之前在数据段准备了一段空间用来安装(复制)中断例程,现在想来完全多此一举。我直接将用户程序代码段的
int9_new地址填入中断向量表,就可以作为中断例程了。由于和用户程序本来就在同一个段,调用其中的子程序肯定也没啥问题。(Good idea!)
成功解决!
3 按一个键后,生成字符串的程序的不动了
参考王爽第17章,关于键盘缓冲区的介绍。(p300)
按下字符键会产生键盘中断并将字符的通码和ascii码写入字符缓冲区中,而使用int 0x16中断例程可以从键盘缓冲区中取出一个键盘输入。但问题是,只有按下按键时会产生int 9中断吗?不,松开时也会产生一个中断,不要忘了每个键都对应这一个通码和一个断码。
于是,每按下一个键并松开的过程如下:
- 按键中断,将键盘输入写入缓冲区 --> 从缓冲区读取一个键盘输入 --> 松开中断 -->
int 0x16因读取不到键盘输入,进入等待
经过尝试,如果按下一个键之后不松开,继续按第二个、第三个键,生成字符串的程序不受影响,继续运行。
int 128 ;在安装本中断前,已将旧int 9的中断号修改为128
mov ah,0
int 0x16 ;(ah)=扫描码, (al)=ascii码mov dh,24
mov dl,79
call put_char
可能的解决方案:
- 自己从端口读取扫描码,然后解析为ascii码,就不会有等待的过程了。可以采用查表。
成功解决!
4 按下字母变绿失效:当数据段加个字节
我在记录头字母的标号后,添加了一个字节定义random_seed db ...,然后前面能跑的按键模块功能突然就寄了。
;...数据段中
head_letter db 0 ;持续记录屏幕上当前最左侧字母的位置(行内偏移)
random_seed db 0x4f ;以此生成下一个随机数,每次生成后会更新
发现问题在这里:
mov bx,[head_letter]
mov es:[0xa0*12 + bx + 1], ah ;将头字符的属性修改为绿色
因为目的操作数是bx,因此从有效地址处取出两个字节,即将random_seed处的字节放到了bx的高字节bh中。
5 伪随机数循环了
参考:随机数大家都会用,但是你知道生成随机数的算法吗? - 知乎 (zhihu.com)
起初使用的是平方取中法,但总是很容易陷入短循环,参数调了几次(循环右移多少位后取右8位)仍然效果极差。

后面感觉在汇编中观察数据的随机性,还是太抽象了。于是我改用了python,尝试了线性同余法: x = ( a ∗ x + b ) % c x=(a*x+b)\%c x=(a∗x+b)%c,取参数组合为 ( a = 217 , b = 11 , c = 253 ) (a=217,b=11,c=253) (a=217,b=11,c=253) 。生成散点图如下左图,横轴是次数,纵轴是生成的随机数值。可以很明显地看出周期性,周期长度在100左右,对于我的小游戏差不多能用了。
将参数c修改为32768(2的15次方)后,效果如右图所示。

6 数字显示不出来
明明感觉代码逻辑没啥问题,pop dx取得的是待显示的一位数字的值,可数字就是显示不出来。
后发现还是字符的值与属性的问题,在显存中每个字符占一个字(即两个字节),第字节是ascii码值,高字节是显示属性。代码中mov es:[di], dx直接写入一个字,dl 是ascii值没错,但dh是零,解释成属性就是黑底黑字。
好吧,原来不是没显示字符,只是显示了而我看不见。
put_one:pop dxadd dx, '0'mov es:[di], dxadd di, 2loop put_one
7 环绕模块卡死
;2 样式表surround_style显示环绕效果
mov ax, style_end - surround_style
mov bx, 2
div bx
mov ah,0 ;有点多余,但比较保险
mov cx,ax
在Bochs中调试时,到div bx这一条指令就会一直卡在这里,不知道是什么情况。

当我将bx修改为bl后,程序可以顺畅地运行下去了。那么应该是因为dx不为0, ( d x , a x ) / b x (dx,ax)/bx (dx,ax)/bx中 bx 值太小(2),发生了除法溢出。很好,这个问题算是解决了,但又出现了一个新的问题:
kkk kk
k k --> k k
kkk kkkk
也不知道这个k是怎么独自跑到下面去的。
surround_style:db -1,-1, -1,0, -1,1db 0,-1, 0,1db 1,-1, 1,0, 1,1style_end:
发现了一个问题:我将相对坐标读取到dx中,高地址dh为行号,低地址dl为列号,即每一对(x,y)应该将行号写在后面,列号写在前面。虽然和我预想的方式不太一样,然而其实没有什么区别,因为都只是空缺了(0,0)这一个组合而已,无法解释最左边一列为什么会错位。
最后,我在胡乱调试中以一种我认为错误的方式,得到了我认为正确的结果。
surround_style:db -1,-2, 0,-1, 1,-1db -1,-1, 1,0,db -1,0, 0,1, 1,1style_end:
相关文章:
【编程实践】黑框框里的打字小游戏,但是汇编语言
开始: 在学习王爽的《汇编语言》的过程中,我就真切地体会到编程实践对于理解的帮助。起初我没有安装书中的实验环境,看到100页左右就开始感觉无趣、吃力,看了后面忘前面,差点就要放弃这本书的学习。好在我后来还是装好…...
ElasticSearch的集群、节点、索引、分片和副本
Elasticsearch是面向文档型数据库,一条数据在这里就是一个文档。为了方便大家理解,我们将Elasticsearch里存储文档数据和关系型数据库MySQL存储数据的概念进行一个类比 ES里的Index可以看做一个库,而Types相当于表,Documents则相当…...
std::cout无法打印uint8_t类型的数据
std::cout在处理uint8_t变量类型的时候默认输出字符,刚好数字0-10对应的ascii字符都是不可打印的 解决: 使用static_cast std::cout << static_cast<int>(time) << std::endl;参考文章:https://blog.csdn.net/weixin_459…...
浅谈泛在电力物联网在智能配电系统应用
贾丽丽 安科瑞电气股份有限公司 上海嘉定 201801 摘要:在社会经济和科学技术不断发展中,配电网实现了角色转变,传统的单向供电服务形式已经被双向能流服务形式取代,社会多样化的用电需求也得以有效满足。随着物联网技术的发展&am…...
已解决:云原生领域的超时挂载Bug — Kubernetes深度剖析
🌷🍁 博主猫头虎(🐅🐾)带您 Go to New World✨🍁 🦄 博客首页——🐅🐾猫头虎的博客🎐 🐳 《面试题大全专栏》 🦕 文章图文…...
概念解析 | 高光谱图像:揭开自然世界的神秘面纱
注1:本文系“概念解析”系列之一,致力于简洁清晰地解释、辨析复杂而专业的概念。本次辨析的概念是:高光谱图像 高光谱图像:揭开自然世界的神秘面纱 Hyperspectral imaging - Wikipedia 背景介绍 我们生活的世界充满了丰富多彩的颜色。这些颜色来源于各种物体反射或吸收不同波长…...
Java类和对象(1)
🐵本篇文章将会开始对类和对象的第一部分讲解 一、简单描述类和对象 对象可以理解为一个实体,在现实生活中,比如在创建一个建筑之前,要先有一个蓝图,这个蓝图用来描述这个建筑的各种属性;此时蓝图就是类&a…...
百度上海智能研发中心一面
Prometheus告警机制原理 介绍hashmap和concurrentHashmap concurrentHashmap和hashmap如果线程1在遍历 另一个线程对这个map进行修改操作 会发生什么现象 对线程安全的理解 通过什么方法解决线程安全 除了上锁 CAS等还有其他手段 不用锁的话 (集合的类设计成一…...
硝烟后的茶歇 | 中睿天下谈攻防演练之邮件攻击溯源实战分享
近日,由中国信息协会信息安全专业委员会、深圳市CIO协会、PCSA安全能力者联盟主办的《硝烟后的茶歇广东站》主题故事会在深圳成功召开。活动已连续举办四年四期,共性智慧逐步形成《年度红蓝攻防系列全景图》、《三化六防“挂图作战”》等共性研究重要成果…...
Leetcode Hot 100之四:283. 移动零+11. 盛最多水的容器
283.移动零 题目: 给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。 请注意 ,必须在不复制数组的情况下原地对数组进行操作。 示例 1: 输入: nums [0,1,0,3,12] 输出: [1,3,12,0,0] …...
景联文科技助力金融机构强化身份验证,提供高质量人像采集服务
随着社会的数字化和智能化进程的加速,人像采集在金融机构身份认证领域中发挥重要作用,为人们的生活带来更多便利和安全保障。 金融机构在身份验证上的痛点主要包括以下方面: 身份盗用和欺诈风险:传统身份验证方式可能存在漏洞&am…...
Spring Cloud LoadBalancer基础知识
LoadBalancer 概念常见的负载均衡策略使用随机选择的负载均衡策略创建随机选择负载均衡器配置 Nacos 权重负载均衡器创建 Nacos 负载均衡器配置 自定义负载均衡器(根据IP哈希策略选择)创建自定义负载均衡器封装自定义负载均衡器配置 缓存 概念 LoadBalancer(负载均衡器)是一种…...
剖析WPF模板机制的内部实现
剖析WPF模板机制的内部实现 众所周知,在WPF框架中,Visual类是可以提供渲染(render)支持的最顶层的类,所有可视化元素(包括UIElement、FrameworkElment、Control等)都直接或间接继承自Visual类。…...
计算机网络常见的名词解释
计算机网络常见的名词解释 1.应用层2.传输层3. 网络层4.链路层5. 无线网络和移动网络6.计算机网络中的安全 1.应用层 API (Application Programming Interface)应用程序编程接口HTTP (Hyper Text Transfer Protocol) 超文本传输协…...
Android Studio导入,删除第三方库
Android项目经常用到无私的程序员们提供的第三方类库。本篇博客就是实现第三方库的导入和删除。 一、导入第三方库 1、将需要的库下载到本地; 2、新建Moudle (1)File --- New Moudle (2)选择Android Library --- Next (3)填写Moudle名 --- Finish。一个新的Mou…...
生成指定长度的随机数字,用对方法精准提效数10倍!
生成指定长度的随机数字这一函数功能可能在以下情况下被使用: 密码生成:在需要生成随机密码时,可以使用该功能生成指定长度的随机数字作为密码。 随机数生成:在需要生成一定长度的随机数列时,可以使用该功能生成随机…...
Vue3 + Naive-ui Data Table 分页页码显示不全
当使用naive-ui 表格并且使用分页组件的时候 需要增加 remote...
机器学习中的决策阈值
什么是决策阈值? sklearn不允许我们直接设置决策阈值,但它允许我们访问用于进行预测的决策分数(决策函数o/p)。我们可以从决策函数输出中选择最佳得分并将其设置为决策阈值,并且将小于该决策阈值的所有那些决策得分值…...
mongodb导出聚合查询的数据
❗️❗️❗️在正文之前先要讲一个坑,就是mongoexport这个命令工具不支持导出聚合查询的数据,比如通过某某字段来分组 我查了一天关于mongoexport怎么来导出聚合查询的结果集,最终还是gpt给了我答案 😭 既然mongoexport不支持&…...
U-Mail信创邮件系统解决方案
近年来,在国家政策的大力引导和自身数字化转型需求驱动下,国产化成为国内数字化发展道路上的关键词,企业不断加强自主创新能力,进行信创建设,实现软硬件系统国产化替代,已成为大势所趋。邮件系统作为企业管…...
大型活动交通拥堵治理的视觉算法应用
大型活动下智慧交通的视觉分析应用 一、背景与挑战 大型活动(如演唱会、马拉松赛事、高考中考等)期间,城市交通面临瞬时人流车流激增、传统摄像头模糊、交通拥堵识别滞后等问题。以演唱会为例,暖城商圈曾因观众集中离场导致周边…...
理解 MCP 工作流:使用 Ollama 和 LangChain 构建本地 MCP 客户端
🌟 什么是 MCP? 模型控制协议 (MCP) 是一种创新的协议,旨在无缝连接 AI 模型与应用程序。 MCP 是一个开源协议,它标准化了我们的 LLM 应用程序连接所需工具和数据源并与之协作的方式。 可以把它想象成你的 AI 模型 和想要使用它…...
鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院挂号小程序
一、开发准备 环境搭建: 安装DevEco Studio 3.0或更高版本配置HarmonyOS SDK申请开发者账号 项目创建: File > New > Create Project > Application (选择"Empty Ability") 二、核心功能实现 1. 医院科室展示 /…...
ffmpeg(四):滤镜命令
FFmpeg 的滤镜命令是用于音视频处理中的强大工具,可以完成剪裁、缩放、加水印、调色、合成、旋转、模糊、叠加字幕等复杂的操作。其核心语法格式一般如下: ffmpeg -i input.mp4 -vf "滤镜参数" output.mp4或者带音频滤镜: ffmpeg…...
在WSL2的Ubuntu镜像中安装Docker
Docker官网链接: https://docs.docker.com/engine/install/ubuntu/ 1、运行以下命令卸载所有冲突的软件包: for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do sudo apt-get remove $pkg; done2、设置Docker…...
Android Bitmap治理全解析:从加载优化到泄漏防控的全生命周期管理
引言 Bitmap(位图)是Android应用内存占用的“头号杀手”。一张1080P(1920x1080)的图片以ARGB_8888格式加载时,内存占用高达8MB(192010804字节)。据统计,超过60%的应用OOM崩溃与Bitm…...
【碎碎念】宝可梦 Mesh GO : 基于MESH网络的口袋妖怪 宝可梦GO游戏自组网系统
目录 游戏说明《宝可梦 Mesh GO》 —— 局域宝可梦探索Pokmon GO 类游戏核心理念应用场景Mesh 特性 宝可梦玩法融合设计游戏构想要素1. 地图探索(基于物理空间 广播范围)2. 野生宝可梦生成与广播3. 对战系统4. 道具与通信5. 延伸玩法 安全性设计 技术选…...
Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信
文章目录 Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信前言一、网络通信基础概念二、服务端与客户端的完整流程图解三、每一步的详细讲解和代码示例1. 创建Socket(服务端和客户端都要)2. 绑定本地地址和端口&#x…...
Qt 事件处理中 return 的深入解析
Qt 事件处理中 return 的深入解析 在 Qt 事件处理中,return 语句的使用是另一个关键概念,它与 event->accept()/event->ignore() 密切相关但作用不同。让我们详细分析一下它们之间的关系和工作原理。 核心区别:不同层级的事件处理 方…...
comfyui 工作流中 图生视频 如何增加视频的长度到5秒
comfyUI 工作流怎么可以生成更长的视频。除了硬件显存要求之外还有别的方法吗? 在ComfyUI中实现图生视频并延长到5秒,需要结合多个扩展和技巧。以下是完整解决方案: 核心工作流配置(24fps下5秒120帧) #mermaid-svg-yP…...
