Linux 详细介绍strace命令
system call(系统调用)是程序向内核请求服务的一种编程方式,strace是一个功能强大的工具,可以跟踪用户进程和 Linux 内核之间的交互。
要了解操作系统如何工作,首先需要了解系统调用如何工作。操作系统的主要功能之一是为用户程序提供了一个抽象。
操作系统大致可以分为两种模式:
内核模式(Kernel mode:):操作系统内核使用的特权且强大的模式
用户模式(User mode):大多数用户应用程序运行的地方
用户主要使用命令行程序和图形用户界面 (GUI) 来完成日常任务。系统调用在后台默默工作,与内核交互以完成工作。
system call(系统调用)与function call(函数调用)非常相似,都接受并处理参数和返回值。唯一的区别是system call进入内核,而function call则不进入内核。从用户空间切换到内核空间是使用特殊的trap机制完成的。
下面将通过一些通用命令来使用 strace 分析每个命令进行的系统调用,并探索一些实际示例。 范例将使用 Red Hat Enterprise Linux,这些命令在其他 Linux 发行版上的工作方式应该也相同:
[root@sandbox ~]# cat /etc/redhat-release
Red Hat Enterprise Linux Server release 7.7 (Maipo)
[root@sandbox ~]#
[root@sandbox ~]# uname -r
3.10.0-1062.el7.x86_64
[root@sandbox ~]#
首先,确保系统上安装了所需的工具。 使用下面的 RPM 命令验证是否安装了 strace; 并使用 -V 选项检查 strace 实用程序版本号:
[root@sandbox ~]# rpm -qa | grep -i strace
strace-4.12-9.el7.x86_64
[root@sandbox ~]#
[root@sandbox ~]# strace -V
strace -- version 4.12
[root@sandbox ~]#
如果没有安装,使用如下命令安装
yum install strace
基于演示的目的,在 /tmp 中创建一个测试目录,并使用 touch 命令创建两个文件:
[root@sandbox ~]# cd /tmp/
[root@sandbox tmp]#
[root@sandbox tmp]# mkdir testdir
[root@sandbox tmp]#
[root@sandbox tmp]# touch testdir/file1
[root@sandbox tmp]# touch testdir/file2
[root@sandbox tmp]#
我使用 /tmp 目录是因为每个人都可以访问它,其实也可以选择其他目录。)
验证文件是否是在 testdir 目录上使用 ls 命令创建的:
[root@sandbox tmp]# ls testdir/
file1 file2
[root@sandbox tmp]#
可能每天都使用 ls 命令,但其实他的工作是基于到系统调用之上。它的工作原理如下:
Command-line utility -> Invokes functions from system libraries (glibc) -> Invokes system calls
ls 命令在 Linux 上内部调用系统库(又名 glibc)中的函数。 这些库调用完成大部分工作的系统调用。
如果想知道从 glibc 库调用了哪些函数,可以使用 ltrace 命令,后跟常规 ls testdir/ 命令:
ltrace ls testdir/
如果没有安装,可以使用如下命令安装
yum install ltrace
一堆输出将被转储到屏幕上; 不用担心——只要跟着做就可以了。 ltrace 命令输出中与本示例相关的一些重要库函数包括:
opendir("testdir/") = { 3 }
readdir({ 3 }) = { 101879119, "." }
readdir({ 3 }) = { 134, ".." }
readdir({ 3 }) = { 101879120, "file1" }
strlen("file1") = 5
memcpy(0x1665be0, "file1\0", 6) = 0x1665be0
readdir({ 3 }) = { 101879122, "file2" }
strlen("file2") = 5
memcpy(0x166dcb0, "file2\0", 6) = 0x166dcb0
readdir({ 3 }) = nil
closedir({ 3 })
通过查看上面的输出,可能可以理解发生了什么。 opendir 库函数正在打开一个名为 testdir 的目录,然后调用 readdir 函数来读取该目录的内容。 最后,调用 closedir 函数,该函数关闭之前打开的目录。 暂时忽略其他 strlen 和 memcpy 函数。
可以看到正在调用哪些库函数,但本文将重点讨论由系统库函数调用的系统调用。
与上面类似,要了解调用了哪些系统调用,只需将 strace 放在 ls testdir 命令之前即可,如下所示。 再次,一堆乱码将被转储到您的屏幕上
[root@sandbox tmp]# strace ls testdir/
execve("/usr/bin/ls", ["ls", "testdir/"], [/* 40 vars */]) = 0
brk(NULL) = 0x1f12000
<<< truncated strace output >>>
write(1, "file1 file2\n", 13file1 file2
) = 13
close(1) = 0
munmap(0x7fd002c8d000, 4096) = 0
close(2) = 0
exit_group(0) = ?
+++ exited with 0 +++
[root@sandbox tmp]#
运行 strace 命令后屏幕上的输出只是为运行 ls 命令而进行的系统调用。 每个系统调用都有特定的操作系统用途,它们可以大致分为以下几部分:
1.Process management system calls
2.File management system calls
3.Directory and filesystem management system calls
4.Other system calls
分析转储到屏幕上的信息的一种更简单的方法是使用 strace 的 -o 选项将输出记录到文件中。 在 -o 标志后添加合适的文件名并再次运行命令:
[root@sandbox tmp]# strace -o trace.log ls testdir/
file1 file2
[root@sandbox tmp]#
这次,没有输出转储到屏幕上 - ls 命令按预期工作,显示文件名并将所有输出记录到文件 trace.log 中。 仅一个简单的 ls 命令,该文件就有近 100 行内容:
[root@sandbox tmp]# ls -l trace.log
-rw-r--r--. 1 root root 7809 Oct 12 13:52 trace.log
[root@sandbox tmp]#
[root@sandbox tmp]# wc -l trace.log
114 trace.log
[root@sandbox tmp]#
看一下示例的trace.log 中的第一行:
execve("/usr/bin/ls", ["ls", "testdir/"], [/* 40 vars */]) = 0
1.该行的 execve 是正在执行的系统调用的名称。
2.括号内的文本是提供给系统调用的参数。
3.= 符号后面的数字(在本例中为 0)是 execve 系统调用返回的值。
这只是范本解释, 可以应用相同的逻辑来理解其他行。
现在,将注意力集中到调用的单个命令,即 ls testdir。 知道命令 ls 使用的目录名称,grep testdir trace.log 详细查看每一行结果:
[root@sandbox tmp]# grep testdir trace.log
execve("/usr/bin/ls", ["ls", "testdir/"], [/* 40 vars */]) = 0
stat("testdir/", {st_mode=S_IFDIR|0755, st_size=32, ...}) = 0
openat(AT_FDCWD, "testdir/", O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC) = 3
[root@sandbox tmp]#
回顾一下上面对execve的分析,能看出这个系统调用是做什么的吗?
execve("/usr/bin/ls", ["ls", "testdir/"], [/* 40 vars */]) = 0
不需要记住所有的系统调用或它们的作用,因为您可以在需要时参考文档。 手册页来救援! 在运行 man 命令之前确保安装了以下软件包:
[root@sandbox tmp]# rpm -qa | grep -i man-pages
man-pages-3.53-5.el7.noarch
[root@sandbox tmp]#
请记住,需要在 man 命令和需要查询的系统调用名称之间添加 2。 如果使用 man man 阅读 man 的手册页,可以看到第 2 部分是为系统调用保留的。 同样,如果需要库函数的信息,则需要在man和库函数名之间添加3。
[root@sandbox tmp]# man man1 Executable programs or shell commands2 System calls (functions provided by the kernel)3 Library calls (functions within program libraries)4 Special files (usually found in /dev)5 File formats and conventions eg /etc/passwd6 Games7 Miscellaneous (including macro packages and conventions), e.g. man(7), groff(7)8 System administration commands (usually only for root)9 Kernel routines [Non standard]
以下 man 命令查看上面范例中涉及的execve系统调用的文档:
man 2 execve
输出如下:
EXECVE(2) Linux Programmer’s Manual EXECVE(2)DESCRIPTIONexecve() executes the program pointed to by filename. filename must be either a binary executable, or a script starting with a line of the form "#! interpreter [arg]". In the latter case, the interpreter must be avalid pathname for an executable which is not itself a script, which will be invoked as interpreter [arg] filename
根据 execve 手册页说名,这个execve系统调用会执行一个作为参数传入的程序(在本例中为 ls)。 还可以向 ls 提供其他参数,例如本示例中的 testdir。 因此,该系统调用仅以 testdir 作为参数运行 ls:
下一个名为 stat 的系统调用使用 testdir 参数:
stat("testdir/", {st_mode=S_IFDIR|0755, st_size=32, ...}) = 0
使用 man 2 stat 访问文档。 stat 是获取文件状态的系统调用 - 请记住,Linux 中的所有内容都是文件,包括目录。
接下来,openat 系统调用打开 testdir。 留意返回的 3。 这是文件描述,后面的系统调用会用到:
openat(AT_FDCWD, "testdir/", O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC) = 3
到目前为止,一切都很好。 现在,打开trace.log 文件并转到openat 系统调用后面的行。 将看到 getdents 系统调用被调用,它执行执行 ls testdir 命令所需的大部分操作。 现在,从trace.log 文件中grep getdents:
[root@sandbox tmp]# grep getdents trace.log
getdents(3, /* 4 entries */, 32768) = 112
getdents(3, /* 0 entries */, 32768) = 0
[root@sandbox tmp]#
man getdents,我们将得知getdents = get directory entries,这里注意,getdents 的参数是 3,它是上面 openat 系统调用中的文件描述符。
现在您已经有了目录列表,需要一种在终端中显示它的方法。 因此,grep 另一个系统调用 write,用于在将输出的内容写入终端:
[root@sandbox tmp]# grep write trace.log
write(1, "file1 file2\n", 13) = 13
[root@sandbox tmp]#
在这些参数中,您可以看到将显示的文件名:file1 和 file2。 关于第一个参数(1),请记住在 Linux 中,当任何进程运行时,默认情况下会为其打开三个文件描述符。 以下是默认的文件描述符:
0 - Standard input
1 - Standard out
2 - Standard error
因此,write 系统调用正在"1 - Standard out"上显示 file1 和 file2,默认将输出到显示屏幕上,由 1 标识。
现在知道哪些系统调用完成了 ls testdir/ 命令的大部分工作。 但是trace.log 文件中的其他100 多个系统调用又如何呢? 操作系统必须执行大量内部工作才能运行进程,因此在日志文件中看到的很多内容都是initialization 和cleanup。 阅读整个trace.log 文件并尝试了解发生了什么使ls 命令正常工作。
现在知道如何分析给定命令的系统调用,可以将此知识用于其他命令来了解正在执行哪些系统调用。 strace 提供了许多有用的命令行选项,使strace过程更轻松,下面介绍了其中一些选项。
默认情况下,strace 不包含所有系统调用信息。 但是,它有一个方便的 -v verbose 选项,可以提供有关每个系统调用的附加信息:
strace -v ls testdir
运行 strace 命令时始终使用 -f 选项是一个很好的做法。 它允许 strace 跟踪当前正在跟踪的进程创建的任何子进程:
strace -f ls testdir
假设只需要系统调用的名称、它们运行的次数以及每个系统调用所花费的时间百分比。 您可以使用 -c 选项来获取这些统计信息:
strace -c ls testdir/
假设想专注于特定的系统调用,例如专注于open系统调用而忽略其余的。 您可以使用 -e 选项后跟系统调用名称:
[root@sandbox tmp]# strace -e open ls testdir
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
open("/lib64/libselinux.so.1", O_RDONLY|O_CLOEXEC) = 3
open("/lib64/libcap.so.2", O_RDONLY|O_CLOEXEC) = 3
open("/lib64/libacl.so.1", O_RDONLY|O_CLOEXEC) = 3
open("/lib64/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
open("/lib64/libpcre.so.1", O_RDONLY|O_CLOEXEC) = 3
open("/lib64/libdl.so.2", O_RDONLY|O_CLOEXEC) = 3
open("/lib64/libattr.so.1", O_RDONLY|O_CLOEXEC) = 3
open("/lib64/libpthread.so.0", O_RDONLY|O_CLOEXEC) = 3
open("/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3
file1 file2
+++ exited with 0 +++
[root@sandbox tmp]#
如果您想专注于多个系统调用,可以使用相同的 -e 命令行选项,并在两个系统调用之间使用逗号。 例如,要查看 write 和 getdents 系统调用:
[root@sandbox tmp]# strace -e write,getdents ls testdir
getdents(3, /* 4 entries */, 32768) = 112
getdents(3, /* 0 entries */, 32768) = 0
write(1, "file1 file2\n", 13file1 file2
) = 13
+++ exited with 0 +++
[root@sandbox tmp]#
到目前为止的示例都是显式地跟踪运行的命令。 但是那些已经运行并且正在执行的命令呢? 例如,如果想跟踪只是长时间运行的进程的daemon(守护进程),该怎么办? 为此,strace 提供了一个特殊的 -p 选项,可以向其提供进程 ID。
替代在一个守护进程上运行strace命令,这里我们以cat 命令为例进行演示,如果提供文件名给cat命令作为参数,这个命令通常会显示文件的内容。 如果没有给出参数,cat 命令只是在终端等待用户输入文本。 输入文本后,它会重复给定的文本,直到用户按 Ctrl+C 退出。
从一个终端运行 cat 命令; 它会显示一个提示,然后只需等待(记住 cat 仍在运行并且尚未退出):
[root@sandbox tmp]# cat
从另一个终端,使用 ps 命令查找进程标识符 (PID):
[root@sandbox ~]# ps -ef | grep cat
root 22443 20164 0 14:19 pts/0 00:00:00 cat
root 22482 20300 0 14:20 pts/1 00:00:00 grep --color=auto cat
[root@sandbox ~]#
现在,使用 -p 选项和 PID(上面使用 ps 找到的)对正在运行的进程运行 strace。 运行 strace 后,输出会显示进程所附加的内容以及 PID 号。 现在,strace 正在跟踪 cat 命令发出的系统调用。 您看到的第一个系统调用是 read,它正在等待来自 0 或标准输入的输入,这是运行 cat 命令的终端:
[root@sandbox ~]# strace -p 22443
strace: Process 22443 attached
read(0,
现在,返回到运行 cat 命令的终端并输入一些文本。 我输入 x0x0 是出于演示目的。 请注意 cat 是如何简单地重复我输入的内容的; 因此,x0x0 出现两次。 我输入第一个,第二个是 cat 命令重复的输出:
[root@sandbox tmp]# cat
x0x0
x0x0
返回到 strace 连接到 cat 进程的终端。 现在会看到两个额外的系统调用:之前的 read 系统调用,现在在终端中读取 x0x0,另一个用于 write,它将 x0x0 写回终端,还有一个新的 read,它正在等待从终端读取。 请注意,标准输入 (0) 和标准输出 (1) 均位于同一终端中:
[root@sandbox ~]# strace -p 22443
strace: Process 22443 attached
read(0, "x0x0\n", 65536) = 5
write(1, "x0x0\n", 5) = 5
read(0,
想象一下,当对守护进程运行 strace 以查看它在后台执行的所有操作时,这有多么有用。 按 Ctrl+C 退出cat 命令; 这也将会终止strace 会话,因为该进程不再运行。
如果想查看所有系统调用的时间戳,只需将 -t 选项与 strace 结合使用即可:
14:24:47 execve("/usr/bin/ls", ["ls", "testdir/"], [/* 40 vars */]) = 0
14:24:47 brk(NULL) = 0x1f07000
14:24:47 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f2530bc8000
14:24:47 access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
14:24:47 open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
如果想知道系统调用之间所花费的时间, strace 有一个方便的 -r 命令,可以显示执行每个系统调用所花费的时间。 非常有用
[root@sandbox ~]#strace -r ls testdir/
0.000000 execve("/usr/bin/ls", ["ls", "testdir/"], [/* 40 vars */]) = 0
0.000368 brk(NULL) = 0x1966000
0.000073 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fb6b1155000
0.000047 access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
0.000119 open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
结论
strace 实用程序对于理解 Linux 上的系统调用非常方便。 要了解其其他命令行选项,可参阅手册页和在线文档。
相关文章:
Linux 详细介绍strace命令
system call(系统调用)是程序向内核请求服务的一种编程方式,strace是一个功能强大的工具,可以跟踪用户进程和 Linux 内核之间的交互。 要了解操作系统如何工作,首先需要了解系统调用如何工作。操作系统的主要功能之一是为用户程序提供了一个…...

【知识分享】__RS485-嵌入式常用的通信协议
目录 前言 一、RS485简介 什么是串口 什么是串行通信 什么是并行通信 二、接口原理 1. 连接方式 2. 差分信号 三、485通讯接口的优势 1. 接口电平低, 不易损坏芯片。 2. 传输速率高 3. 抗干扰能力强 4. 传输距离远,支持节点多。 四、常见…...

Qt生成动态链接库并使用动态链接库
项目结构 整个工程由一个主程序构成和一个模块构成(dll)。整个工程的结构目录如下 Define.priMyProject.proMyProject.pro.user ---bin ---MainProgrammain.cppMainProgram.proMainProgram.pro.userwidget.cppwidget.hwidget.ui ---MathDllMathDll.proMathDll.pro.userMyMath.…...

E4990A 阻抗分析仪,20 Hz 至 10/20/30/50/120 MHz
01 E4990A 阻抗分析仪 20 Hz 至 10/20/30/50/120 MHz 产品综述: E4990A 阻抗分析仪具有 20 Hz 至 120 MHz 的频率范围,可在宽阻抗范围内提供出色的 0.045%(典型值)基本准确度,并内置 40 V 直流偏置源,适…...

k8s volumes and data
Overview 传统上,容器引擎(Container Engine)不提供比容器寿命更长的存储。由于容器被认为是瞬态(transient)的,这可能会导致数据丢失或复杂的外部存储选项。Kubernetes卷共享 Pod 生命周期,而不是其中的容器。如果容器终止,数据…...

万宾科技智能水环境综合治理监测系统效果
水环境综合治理是一项旨在全面改善水环境质量的系统工程。它以水体为对象,综合考虑各种因素,通过科学规划和技术手段,解决水环境污染、生态退化等问题,核心理念是“统一规划、分步实施;标本兼治,重在治本&a…...

掌控安全 暖冬杯 CTF Writeup By AheadSec
本来结束时发到了学校AheadSec的群里面了的,觉得这比赛没啥好外发WP的,但是有些师傅来问了,所以还是发一下吧。 文章目录 Web签到:又一个计算题计算器PHP反序列化又一个PHP反序列化 Misc这是邹节伦的桌面背景图什么鬼?…...
jQuery-操作DOM
使用jQuery操作DOM dom : 文档对象模型 就是HTML元素 $() 函数的2个用法: 用法1:放入一个字符串(选择器)表示获取元素 例如 $("p") $("#abc") $(".del") 用法2:放入一个函数,表示文档就绪函数 例如 $(function(){代…...

高级网工在Linux服务器抓包,少不了这几条常用的tcpdump命令。
Linux 的命令太多,tcpdump 是一个非常强大的抓包命令。有时候想看线上发生的一些问题: nginx 有没有客户端连接过来…… 客户端连接过来的时候 Post 上来的数据对不对…… 我的 Redis 实例到底是哪些业务在使用…… tcpdump 作为网络分析神器就派上用场…...
Hough算法数学原理
直线的极坐标方程: x x 0 r cos θ x x_0 r\cos \theta xx0rcosθ y y 0 r sin θ y y_0 r\sin \theta yy0rsinθ x cos θ x 0 cos θ r cos 2 θ x \cos \theta x_0 \cos \theta r \cos^2 \theta xcosθx0cosθrcos2θ y sin θ…...
基于Debain安装 Docker 和 Docker Compose
一、安装Docker # 先升级一下系统 (Ubuntu / Debian 系) sudo apt-get update sudo apt-get upgrade# 如果你是 CentOS、红帽系列则使用: yum update yum upgrade# 安装 Docker curl -fsSL https://get.docker.com -o get-docker.sh sudo sh get-docker.sh二、Dock…...

gittee使用教学
一、git简介 Git是一个开源的分布式版本控制系统,用于敏捷高效的处理任何大小项目的版本管理。 核心功能: 项目的版本管理 团队协同开发 二、准备工作 1、下载 Git 2、除了选择安装位置以外,其他都无脑安装 3、检查一下安装情况 win…...
q2-qt-多线程
是的,Qt框架中提供了专门用于线程池的API。Qt的线程池API位于QtConcurrent命名空间下,以及QThreadPool类中。 QtConcurrent命名空间提供了一些高级的API,可以方便地使用线程池来执行并行任务。其中,QtConcurrent::run()函数可以用…...

指针,函数指针,二级指针,指针传参,回调函数,指针步长
文章目录 指针是什么?指针的定义指针的大小 指针类型指针有哪些类型?指针类型有什么意义?代码演示:(偏移)代码演示(指针解引用时取出的字节数)其他例子 野指针野指针的成因如何避免野指针 指针运算指针整数指针-指针指针的关系运算…...
StringUtils.isEmpty()方法过期的替代方法
1、问题概述? 今天在准备使用StringUtils.isEmpty()工具判断字符串是否为空的时候,突然发现idEmpty上出现了横线,这就表示这个方法可以实现但是已经过期了,官方不推荐使用了。 原因其实是因为有人给官方提交了一个问题ÿ…...

智慧电力运维综合辅助监控系统
智慧电力运维综合辅助监控系统是一种基于现代信息技术的电力运维管理工具,旨在提高电力运行安全,降低运维成本,提高服务质量。依托电易云-智慧电力物联网,该系统通过多种传感器和现场监测装置,远程在线监测、监视电力设…...
v-model和:model的区别
问题 在我们使用Element plus框架时,经常会遇到表单,比如代码块: <el-form ref"ruleFormRef" :model"ruleForm" :rules"rules" label-width"120px" class"demo-ruleForm" :size"…...

网络攻击(二)--情报搜集阶段
4.1. 概述 在情报收集阶段,你需要采用各种可能的方法来收集将要攻击的客户组织的所有信息,包括使用社交网络、Google Hacking技术、目标系统踩点等等。 而作为渗透测试者,你最为重要的一项技能就是对目标系统的探查能力,包括获知…...
oracle异常:ORA-03297:文件包含在请求的 RESIZE 值以外使用的数据
出现这个问题,主要是在对表空间扩容的时候,扩容的大小<实际数据文件大小 1、扩容的语句 alter database datafile D:\APP\ADMINISTRATOR\ORADATA\ORCL\USER.DBF resize 2G; 2、若何确定扩容大小是否比实际文件大 根据路径找到文件,查看…...

Redis 环境搭建
文章目录 第1关:Redis 环境搭建 第1关:Redis 环境搭建 编程要求 根据上述相关知识,在右侧命令行中完成 Redis 集群的部署与安装。 安装完成后,使用 echo “cluster nodes”|redis-cli -p 7001 -c >/root/test.txt 将结果保存。…...

云启出海,智联未来|阿里云网络「企业出海」系列客户沙龙上海站圆满落地
借阿里云中企出海大会的东风,以**「云启出海,智联未来|打造安全可靠的出海云网络引擎」为主题的阿里云企业出海客户沙龙云网络&安全专场于5.28日下午在上海顺利举办,现场吸引了来自携程、小红书、米哈游、哔哩哔哩、波克城市、…...
vue3 字体颜色设置的多种方式
在Vue 3中设置字体颜色可以通过多种方式实现,这取决于你是想在组件内部直接设置,还是在CSS/SCSS/LESS等样式文件中定义。以下是几种常见的方法: 1. 内联样式 你可以直接在模板中使用style绑定来设置字体颜色。 <template><div :s…...
在四层代理中还原真实客户端ngx_stream_realip_module
一、模块原理与价值 PROXY Protocol 回溯 第三方负载均衡(如 HAProxy、AWS NLB、阿里 SLB)发起上游连接时,将真实客户端 IP/Port 写入 PROXY Protocol v1/v2 头。Stream 层接收到头部后,ngx_stream_realip_module 从中提取原始信息…...
Qwen3-Embedding-0.6B深度解析:多语言语义检索的轻量级利器
第一章 引言:语义表示的新时代挑战与Qwen3的破局之路 1.1 文本嵌入的核心价值与技术演进 在人工智能领域,文本嵌入技术如同连接自然语言与机器理解的“神经突触”——它将人类语言转化为计算机可计算的语义向量,支撑着搜索引擎、推荐系统、…...
python如何将word的doc另存为docx
将 DOCX 文件另存为 DOCX 格式(Python 实现) 在 Python 中,你可以使用 python-docx 库来操作 Word 文档。不过需要注意的是,.doc 是旧的 Word 格式,而 .docx 是新的基于 XML 的格式。python-docx 只能处理 .docx 格式…...

零基础设计模式——行为型模式 - 责任链模式
第四部分:行为型模式 - 责任链模式 (Chain of Responsibility Pattern) 欢迎来到行为型模式的学习!行为型模式关注对象之间的职责分配、算法封装和对象间的交互。我们将学习的第一个行为型模式是责任链模式。 核心思想:使多个对象都有机会处…...
代理篇12|深入理解 Vite中的Proxy接口代理配置
在前端开发中,常常会遇到 跨域请求接口 的情况。为了解决这个问题,Vite 和 Webpack 都提供了 proxy 代理功能,用于将本地开发请求转发到后端服务器。 什么是代理(proxy)? 代理是在开发过程中,前端项目通过开发服务器,将指定的请求“转发”到真实的后端服务器,从而绕…...

中医有效性探讨
文章目录 西医是如何发展到以生物化学为药理基础的现代医学?传统医学奠基期(远古 - 17 世纪)近代医学转型期(17 世纪 - 19 世纪末)现代医学成熟期(20世纪至今) 中医的源远流长和一脉相承远古至…...

保姆级教程:在无网络无显卡的Windows电脑的vscode本地部署deepseek
文章目录 1 前言2 部署流程2.1 准备工作2.2 Ollama2.2.1 使用有网络的电脑下载Ollama2.2.2 安装Ollama(有网络的电脑)2.2.3 安装Ollama(无网络的电脑)2.2.4 安装验证2.2.5 修改大模型安装位置2.2.6 下载Deepseek模型 2.3 将deepse…...
Redis:现代应用开发的高效内存数据存储利器
一、Redis的起源与发展 Redis最初由意大利程序员Salvatore Sanfilippo在2009年开发,其初衷是为了满足他自己的一个项目需求,即需要一个高性能的键值存储系统来解决传统数据库在高并发场景下的性能瓶颈。随着项目的开源,Redis凭借其简单易用、…...