LuaJIT 学习(3)—— ffi.* API 函数

news2025/3/16 2:18:39

文章目录

    • Glossary
    • Declaring and Accessing External Symbols
      • `ffi.cdef(def)`
      • `ffi.C`
      • `clib = ffi.load(name [,global])`
        • 例子:ffi.load 函数的使用
    • Creating cdata Objects
      • `cdata = ffi.new(ct [,nelem] [,init...]) `
      • `cdata = ctype([nelem,] [init...])`
        • 例子:匿名 C 结构体
      • `ctype = ffi.typeof(ct)`
      • `cdata = ffi.cast(ct, init)`
        • 例子:ffi.cast 函数的使用
      • `ctype = ffi.metatype(ct, metatable)`
        • 例子:ffi.metatype 函数的使用
      • `cdata = ffi.gc(cdata, finalizer)`
    • C Type Information
      • `size = ffi.sizeof(ct [,nelem])`
      • `align = ffi.alignof(ct)`
      • `ofs [,bpos,bsize] = ffi.offsetof(ct, field)`
      • `status = ffi.istype(ct, obj)`
    • Utility Functions
      • `err = ffi.errno([newerr])`
      • `str = ffi.string(ptr [,len])`
        • 例子:ffi.string 函数的使用
      • `ffi.copy(dst, src, len) `
      • `ffi.copy(dst, str)`
        • 例子:ffi.copy 函数的使用
      • `ffi.fill(dst, len [,c])`
    • Target-specific Information
      • `status = ffi.abi(param)`
      • `ffi.os`
      • `ffi.arch`
    • Methods for Callbacks
      • `cb:free()`
      • `cb:set(func)`
        • 例子:callback 的创建与使用
    • Extended Standard Library Functions
      • `n = tonumber(cdata)`
      • `s = tostring(cdata)`
      • `iter, obj, start = pairs(cdata) `
      • `iter, obj, start = ipairs(cdata)`
    • Extensions to the Lua Parser

Glossary

  • cdecl — An abstract C type declaration (a Lua string).
  • ctype — A C type object. This is a special kind of cdata returned by ffi.typeof(). It serves as a cdata constructor when called.
  • cdata — A C data object. It holds a value of the corresponding ctype.
  • ct — A C type specification which can be used for most of the API functions. Either a cdecl, a ctype or a cdata serving as a template type.
  • cb — A callback object. This is a C data object holding a special function pointer. Calling this function from C code runs an associated Lua function.
  • VLA — A variable-length array is declared with a ? instead of the number of elements, e.g. "int[?]". The number of elements (nelem) must be given when it’s created.
  • VLS — A variable-length struct is a struct C type where the last element is a VLA. The same rules for declaration and creation apply.

LuaJIT 新增了一种数据类型叫 cdata,用来表示 C 语言数据对象。ctypecb 都是一种特殊的 cdata

如果数据类型是 cdata,可以使用 tostring 函数返回一个字符串表示一个 cdatactype 对象的 C 语言类型。

Declaring and Accessing External Symbols

External symbols must be declared first and can then be accessed by indexing a C library namespace, which automatically binds the symbol to a specific library.

ffi.cdef(def)

Adds multiple C declarations for types or external symbols (named variables or functions). def must be a Lua string. It’s recommended to use the syntactic sugar for string arguments as follows:

ffi.cdef[[
typedef struct foo { int a, b; } foo_t;  // Declare a struct and typedef.
int dofoo(foo_t *f, int n);  /* Declare an external C function. */
]]

The contents of the string (the part in green above) must be a sequence of C declarations, separated by semicolons. The trailing semicolon for a single declaration may be omitted.

Please note, that external symbols are only declared, but they are not bound to any specific address, yet. Binding is achieved with C library namespaces (see below).

C declarations are not passed through a C pre-processor, yet. No pre-processor tokens are allowed, except for #pragma pack. Replace #define in existing C header files with enum, static const or typedef and/or pass the files through an external C pre-processor (once). Be careful not to include unneeded or redundant declarations from unrelated header files.

ffi.C

This is the default C library namespace — note the uppercase 'C'. It binds to the default set of symbols or libraries on the target system. These are more or less the same as a C compiler would offer by default, without specifying extra link libraries.

On POSIX systems, this binds to symbols in the default or global namespace. This includes all exported symbols from the executable and any libraries loaded into the global namespace. This includes at least libc, libm, libdl (on Linux), libgcc (if compiled with GCC), as well as any exported symbols from the Lua/C API provided by LuaJIT itself.

On Windows systems, this binds to symbols exported from the *.exe, the lua51.dll (i.e. the Lua/C API provided by LuaJIT itself), the C runtime library LuaJIT was linked with (msvcrt*.dll), kernel32.dll, user32.dll and gdi32.dll.

clib = ffi.load(name [,global])

This loads the dynamic library given by name and returns a new C library namespace which binds to its symbols. On POSIX systems, if global is true, the library symbols are loaded into the global namespace, too.

If name is a path, the library is loaded from this path. Otherwise name is canonicalized in a system-dependent way and searched in the default search path for dynamic libraries:

On POSIX systems, if the name contains no dot, the extension .so is appended. Also, the lib prefix is prepended if necessary. So ffi.load("z") looks for "libz.so" in the default shared library search path.

On Windows systems, if the name contains no dot, the extension .dll is appended. So ffi.load("ws2_32") looks for "ws2_32.dll" in the default DLL search path.

例子:ffi.load 函数的使用

测试的 C 库代码 mytest.c

#include <stdio.h>

void test(void)
{
    printf("hello world!\n");
}

编译成动态库

gcc -o mytest.so -shared mytest.c -fPIC

LuaJIT 中加载并使用这个库

local ffi = require("ffi")
local c = ffi.C

ffi.cdef[[
    void test(void);
]]

-- 第二个参数为 true ,库的符号会加载到 C 库命名空间
ffi.load("./mytest.so", true)
c.test()

-- local mytest = ffi.load("./mytest.so", false)
-- mytest.test()

Creating cdata Objects

The following API functions create cdata objects (type() returns "cdata"). All created cdata objects are garbage collected.

cdata = ffi.new(ct [,nelem] [,init...])

cdata = ctype([nelem,] [init...])

Creates a cdata object for the given ct. VLA/VLS types require the nelem argument. The second syntax uses a ctype as a constructor and is otherwise fully equivalent.

The cdata object is initialized according to the rules for initializers, using the optional init arguments. Excess initializers cause an error.

Performance notice: if you want to create many objects of one kind, parse the cdecl only once and get its ctype with ffi.typeof(). Then use the ctype as a constructor repeatedly.

Please note, that an anonymous struct declaration implicitly creates a new and distinguished ctype every time you use it for ffi.new(). This is probably not what you want, especially if you create more than one cdata object. Different anonymous structs are not considered assignment-compatible by the C standard, even though they may have the same fields! Also, they are considered different types by the JIT-compiler, which may cause an excessive number of traces. It’s strongly suggested to either declare a named struct or typedef with ffi.cdef() or to create a single ctype object for an anonymous struct with ffi.typeof().

例子:匿名 C 结构体
local ffi = require("ffi")

ffi.cdef [[
    typedef struct {
        int x;
        int y;
    } point;
]]

print(tostring(ffi.new("point")))                  --> cdata<struct 97>: 0x7fa13b1bf1d8
print(tostring(ffi.new("point")))                  --> cdata<struct 97>: 0x7fa13b1beff0
print(tostring(ffi.new("struct {int x; int y;}"))) --> cdata<struct 101>: 0x7fa13b1c2e50
-- 会创建新的结构体类型
print(tostring(ffi.new("struct {int x; int y;}"))) --> cdata<struct 104>: 0x7fa13b1c3048

local t = ffi.typeof("struct {int x; int y;}")
print(tostring(t())) --> cdata<struct 107>: 0x7fa13b1c3100
-- 不会创建新的结构体类型
print(tostring(t())) --> cdata<struct 107>: 0x7fa13b1c3198

从输出可以看到,每次调用 ffi.new 创建一个匿名结构体对象都会创建一个新的结构体类型。

使用 ffi.typeof 为匿名结构体创建一个ctype 对象后,用 ctype 创建结构体对象,就不会再创建新的类型。

ctype = ffi.typeof(ct)

Creates a ctype object for the given ct.

This function is especially useful to parse a cdecl only once and then use the resulting ctype object as a constructor.

cdata = ffi.cast(ct, init)

Creates a scalar cdata object for the given ct. The cdata object is initialized with init using the “cast” variant of the C type conversion rules.

This functions is mainly useful to override the pointer compatibility checks or to convert pointers to addresses or vice versa.

例子:ffi.cast 函数的使用
local ffi = require("ffi")

ffi.cdef [[
    typedef struct {
        int x;
        int y;
    } point;
]]

local p = ffi.new("point")
local pp = ffi.cast("point *", p)
pp.x = 1
pp.y = 2
print(p.x)
print(p.y)

使用 ffi.cast 创建一个执行结构体的指针,然后对结构体赋值。

之所以是这样是因为 FFI 语义中C type conversion rules,会先将cdata对象转换成C类型也就是结构体,

然后会将结构体的基地址转换为指针!

ctype = ffi.metatype(ct, metatable)

Creates a ctype object for the given ct and associates it with a metatable. Only struct/union types, complex numbers and vectors are allowed. Other types may be wrapped in a struct, if needed.

The association with a metatable is permanent and cannot be changed afterwards. Neither the contents of the metatable nor the contents of an __index table (if any) may be modified afterwards. The associated metatable automatically applies to all uses of this type, no matter how the objects are created or where they originate from. Note that predefined operations on types have precedence (e.g. declared field names cannot be overridden).

All standard Lua metamethods are implemented. These are called directly, without shortcuts, and on any mix of types. For binary operations, the left operand is checked first for a valid ctype metamethod. The __gc metamethod only applies to struct/union types and performs an implicit ffi.gc() call during creation of an instance.

例子:ffi.metatype 函数的使用
local ffi = require("ffi")

ffi.cdef[[
typedef struct { double x, y; } point_t;
]]

local point
local mt = {
  __add = function(a, b) return point(a.x+b.x, a.y+b.y) end,
  __len = function(a) return math.sqrt(a.x*a.x + a.y*a.y) end,
  __index = {
    area = function(a) return a.x*a.x + a.y*a.y end,
  },
}
point = ffi.metatype("point_t", mt)

local a = point(3, 4)
print(a.x, a.y)  --> 3  4
print(#a)        --> 5
print(a:area())  --> 25
local b = a + point(0.5, 8)
print(#b)        --> 12.5

-- 并不一定需要使用 ffi.metatype 返回的 ctype 来创建数据,只要调用了 ffi.metatype,关联的元表会自动应用到所有该类型的使用上。
local b = ffi.new("point_t", 3, 4)
print(#b)

cdata = ffi.gc(cdata, finalizer)

Associates a finalizer with a pointer or aggregate cdata object. The cdata object is returned unchanged.

This function allows safe integration of unmanaged resources into the automatic memory management of the LuaJIT garbage collector. Typical usage:

local p = ffi.gc(ffi.C.malloc(n), ffi.C.free)
...
p = nil -- Last reference to p is gone.
-- GC will eventually run finalizer: ffi.C.free(p)

A cdata finalizer works like the __gc metamethod for userdata objects: when the last reference to a cdata object is gone, the associated finalizer is called with the cdata object as an argument. The finalizer can be a Lua function or a cdata function or cdata function pointer. An existing finalizer can be removed by setting a nil finalizer, e.g. right before explicitly deleting a resource:

ffi.C.free(ffi.gc(p, nil)) -- Manually free the memory.

C Type Information

The following API functions return information about C types. They are most useful for inspecting cdata objects.

size = ffi.sizeof(ct [,nelem])

Returns the size of ct in bytes. Returns nil if the size is not known (e.g. for "void" or function types). Requires nelem for VLA/VLS types, except for cdata objects.

align = ffi.alignof(ct)

Returns the minimum required alignment for ct in bytes.

ofs [,bpos,bsize] = ffi.offsetof(ct, field)

Returns the offset (in bytes) of field relative to the start of ct, which must be a struct. Additionally returns the position and the field size (in bits) for bit fields.

status = ffi.istype(ct, obj)

Returns true if obj has the C type given by ct. Returns false otherwise.

C type qualifiers (const etc.) are ignored. Pointers are checked with the standard pointer compatibility rules, but without any special treatment for void *. If ct specifies a struct/union, then a pointer to this type is accepted, too. Otherwise the types must match exactly.

Note: this function accepts all kinds of Lua objects for the obj argument, but always returns false for non-cdata objects.

Utility Functions

err = ffi.errno([newerr])

Returns the error number set by the last C function call which indicated an error condition. If the optional newerr argument is present, the error number is set to the new value and the previous value is returned.

This function offers a portable and OS-independent way to get and set the error number. Note that only some C functions set the error number. And it’s only significant if the function actually indicated an error condition (e.g. with a return value of -1 or NULL). Otherwise, it may or may not contain any previously set value.

You’re advised to call this function only when needed and as close as possible after the return of the related C function. The errno value is preserved across hooks, memory allocations, invocations of the JIT compiler and other internal VM activity. The same applies to the value returned by GetLastError() on Windows, but you need to declare and call it yourself.

str = ffi.string(ptr [,len])

Creates an interned Lua string from the data pointed to by ptr.

If the optional argument len is missing, ptr is converted to a "char *" and the data is assumed to be zero-terminated. The length of the string is computed with strlen().

Otherwise ptr is converted to a "void *" and len gives the length of the data. The data may contain embedded zeros and need not be byte-oriented (though this may cause endianess issues).

This function is mainly useful to convert (temporary) "const char *" pointers returned by C functions to Lua strings and store them or pass them to other functions expecting a Lua string. The Lua string is an (interned) copy of the data and bears no relation to the original data area anymore. Lua strings are 8 bit clean and may be used to hold arbitrary, non-character data.

Performance notice: it’s faster to pass the length of the string, if it’s known. E.g. when the length is returned by a C call like sprintf().

例子:ffi.string 函数的使用
local ffi = require("ffi")

local function replace(s)
    local s1 = ffi.new("char [?]", #s)
    ffi.copy(s1, s, #s)
    s1[0] = string.byte("a")
    s1[1] = string.byte("b")
    s1[2] = string.byte("c")
    return ffi.string(s1, #s)
end

local s = replace("123abc")
print(s) -- abcabc

ffi.copy(dst, src, len)

ffi.copy(dst, str)

Copies the data pointed to by src to dst. dst is converted to a "void *" and src is converted to a "const void *".

In the first syntax, len gives the number of bytes to copy. Caveat: if src is a Lua string, then len must not exceed #src+1.

In the second syntax, the source of the copy must be a Lua string. All bytes of the string plus a zero-terminator are copied to dst (i.e. #src+1 bytes).

Performance notice: ffi.copy() may be used as a faster (inlinable) replacement for the C library functions memcpy(), strcpy() and strncpy().

例子:ffi.copy 函数的使用
local ffi = require("ffi")

-- 假设有一个 C 类型的结构体
ffi.cdef[[
typedef struct {
    int a;
    int b;
} MyStruct;
]]

-- 分配内存
local src = ffi.new("MyStruct", 10, 20)
local dst = ffi.new("MyStruct")

-- 使用 ffi.copy 拷贝数据
ffi.copy(dst, src, ffi.sizeof("MyStruct"))

-- 输出目标内存的数据,验证是否拷贝成功
print("dst.a =", dst.a)  -- 10
print("dst.b =", dst.b)  -- 20

ffi.fill(dst, len [,c])

Fills the data pointed to by dst with len constant bytes, given by c. If c is omitted, the data is zero-filled.

Performance notice: ffi.fill() may be used as a faster (inlinable) replacement for the C library function memset(dst, c, len). Please note the different order of arguments!

Target-specific Information

status = ffi.abi(param)

Returns true if param (a Lua string) applies for the target ABI (Application Binary Interface). Returns false otherwise. The following parameters are currently defined:

ParameterDescription
32bit32 bit architecture
64bit64 bit architecture
leLittle-endian architecture
beBig-endian architecture
fpuTarget has a hardware FPU
softfpsoftfp calling conventions
hardfphardfp calling conventions
eabiEABI variant of the standard ABI
winWindows variant of the standard ABI
pauthPointer authentication ABI
uwpUniversal Windows Platform
gc6464 bit GC references

ffi.os

Contains the target OS name. Same contents as jit.os.

ffi.arch

Contains the target architecture name. Same contents as jit.arch.

Methods for Callbacks

The C types for callbacks have some extra methods:

cb:free()

Free the resources associated with a callback. The associated Lua function is unanchored and may be garbage collected. The callback function pointer is no longer valid and must not be called again (it may be reused by a subsequently created callback).

cb:set(func)

Associate a new Lua function with a callback. The C type of the callback and the callback function pointer are unchanged.

This method is useful to dynamically switch the receiver of callbacks without creating a new callback each time and registering it again (e.g. with a GUI library).

例子:callback 的创建与使用
local ffi = require("ffi")

ffi.cdef[[
    typedef void (*func)(int);
]]

local function test_func1(n)
    print(n)
end

local function test_func2(n)
    print(n*2)
end

-- 创建一个 callback
local cb = ffi.cast("func", test_func1)
cb(1) --> 1

cb:set(test_func2)
cb(1) --> 2

-- 释放 callback
cb:free()

Extended Standard Library Functions

The following standard library functions have been extended to work with cdata objects:

n = tonumber(cdata)

Converts a number cdata object to a double and returns it as a Lua number. This is particularly useful for boxed 64 bit integer values. Caveat: this conversion may incur a precision loss.

s = tostring(cdata)

Returns a string representation of the value of 64 bit integers (nnnLL” or nnnULL”) or complex numbers (re±imi”).

Otherwise returns a string representation of the C type of a ctype object (“ctype<type>”) or a cdata object ("cdata<type>: address"), unless you override it with a __tostring metamethod (see ffi.metatype()).

iter, obj, start = pairs(cdata)

iter, obj, start = ipairs(cdata)

Calls the __pairs or __ipairs metamethod of the corresponding ctype.

Extensions to the Lua Parser

The parser for Lua source code treats numeric literals with the suffixes LL or ULL as signed or unsigned 64 bit integers. Case doesn’t matter, but uppercase is recommended for readability. It handles decimal (42LL), hexadecimal (0x2aLL) and binary (0b101010LL) literals.

比如

print(type(123LL)) --> cdata
print(type(123ULL)) --> cdata

The imaginary part of complex numbers can be specified by suffixing number literals with i or I, e.g. 12.5i. Caveat: you’ll need to use 1i to get an imaginary part with the value one, since i itself still refers to a variable named i.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2315746.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

方差,协方差及协方差矩阵的计算

1.方差 方差是用来衡量一组数据的离散程度&#xff0c;数序表达式如下: σ 2 1 N ∑ i 1 N ( x i − μ ) 2 \sigma^2\frac1N\sum_{i1}^N(x_i-\mu)^2 σ2N1​i1∑N​(xi​−μ)2 σ 2 σ^2 σ2表示样本的总体方差&#xff0c; N N N 表示样本总数&#xff0c; x i x _i xi​…

DeepSeek-R1思路训练多模态大模型-Vision-R1开源及实现方法思路

刚开始琢磨使用DeepSeek-R1风格训练多模态R1模型&#xff0c;就看到这个工作&#xff0c;本文一起看看&#xff0c;供参考。 先提出问题&#xff0c;仅靠 RL 是否足以激励 MLLM 的推理能力&#xff1f; 结论&#xff1a;不能&#xff0c;因为如果 RL 能有效激励推理能力&#…

Unity 创建签名证书、获取签名证书信息,证书指纹

目录 一&#xff1a;创建签名证书 二&#xff1a;自动填写密码 ​编辑 三&#xff1a;获取签名证书的信息 后言 &#x1f451;&#x1f451;&#x1f451; 一&#xff1a;创建签名证书 首先确保Unity是安卓打包&#xff0c;然后按图操作 会打开下图页面 选择你要创建到的…

在AIStudio飞桨星河社区一键部署DeepSeek-r1:70b模型

随着DeepSeek的火热&#xff0c;市面上出现大量的第三方的API服务区&#xff0c;但是对于对安全、隐私、控制有一定需求的用户&#xff0c;还是会希望能够自主部署DeepSeek 。 实践下来&#xff0c;用自己的机器部署是一条解决之道&#xff0c;但是推理起来&#xff0c;cpu和内…

机器学习算法分类及应用场景全解析

在机器学习的学习过程中&#xff0c;具备归类思想至关重要。机器学习涉及众多算法、数据类型及应用场景&#xff0c;归类能让我们清晰梳理知识体系。比如将算法按学习方式分为有监督、无监督等&#xff0c;按任务分类分为分类任务、回归任务和生成任务。通过归类&#xff0c;能…

GNU Nano编辑器中,怎样保存并退出

当出现git commit的提交内容需要修改时&#xff0c;使用git commit --amend进行解决。 但是在修改提交的内容时&#xff0c;弹出了GNU Nano的编辑器 修改完毕后&#xff0c;使用ctrlxd的组合键退出 输入Y后&#xff0c;将退出编辑器&#xff0c;操作完成

个人居家 Web移动端 局域网 远程控制电脑 工具 PC遥控器拿去玩吧

想远程电脑 换个电影&#xff0c;切个歌&#xff0c;随有无线键鼠&#xff0c;但解决不了离屏幕较远 看不清鼠标指针和键入内容。 看似简单的事情&#xff0c;但对周末躺下沙发的码农来说&#xff0c;就再也起不了身了。 远程工具 TeamViewer、向日葵、Autodesk以及开源的RustD…

cursor中使用prettier-code formatter插件方法

cursor的"扩展"中搜索"prettier-code formatter"&#xff0c;然后安装 点击cursor编辑器右上角“更多操作”&#xff0c;然后打开“配置编辑器” 按照图片进行操作&#xff0c;进入到editor在editor中&#xff0c;找“格式化“&#xff0c;把Format On Sav…

SpaceSync智能排班:重构未来办公空间的神经中枢

文心智能体平台可免费使用DeepSeek 满血版啦&#xff0c;使用DeepSeek模型创建并提交智能体&#xff0c;即有机会瓜分万元奖金&#xff01;有这等好事还不快冲&#xff01; 文心智能体官网&#xff1a;文心智能体平台AgentBuilder | 想象即现实 本片文章为作者参加文心智能体平…

ToB公司找客户专用|大数据获客系统

对于ToB公司而言&#xff0c;找到并吸引合适的潜在客户并非易事。传统的获客手段如参加行业展会、电话推销以及直接拜访等&#xff0c;虽然在过去取得了一定成效&#xff0c;但如今却暴露出诸多问题。首先&#xff0c;这些方法往往成本高昂&#xff0c;无论是时间还是金钱上的投…

Linux 文件权限类

目录 文件属性 从左到右的10个字符表示 rwx作用文件和目录的不同解释 图标&#xff1a; 案例实操 chmod 改变权限 基本语法 经验技巧 案例实操 拓展&#xff1a;可以通过一个命令查看用户列表 chown改变所有者 基本语法 选项说明 案例实操 chgrp 改变所属组 基…

在线Doc/Docx转换为PDF格式 超快速转换的一款办公软件 文档快速转换 在线转换免费转换办公软件

小白工具https://www.xiaobaitool.net/files/word-pdf/提供了一项非常实用的在线服务——将Doc或Docx格式的文档快速转换为PDF格式。这项服务不仅操作简单&#xff0c;而且转换效率高&#xff0c;非常适合需要频繁处理文档转换的用户。 服务特点&#xff1a; 批量转换&#x…

网络安全——SpringBoot配置文件明文加密

XTHS&#xff1a;第一步、XTHS&#xff1a;第二步、XTHS&#xff1a;第三步、XTHS&#xff1a;第四步 &#xff01;就可以实现了。&#xff08;但是前提&#xff0c;你要先对你的文本进行加密&#xff0c;然后按照ENC(加密文本)&#xff0c;放到配置文件中&#xff09; 一、前言…

Docker安装Kafka(内含zookeeper)

因为kafka是基于zookeeper做的&#xff0c;所以必须要有zookeeper 一、Zookeeper 1.拉取镜像 docker pull zookeeper:3.7.02.运行 docker run --restartalways \--log-driver json-file \--log-opt max-size100m \--log-opt max-file2 \--name zookeeper -p 2181:2181 \-v…

Netty启动源码NioEventLoop剖析accept剖析read剖析write剖析

学习链接 NIO&Netty - 专栏 Netty核心技术十–Netty 核心源码剖析Netty核心技术九–TCP 粘包和拆包及解决方案Netty核心技术七–Google ProtobufNetty核心技术六–Netty核心模块组件Netty核心技术五–Netty高性能架构设计 聊聊Netty那些事儿 - 专栏 一文搞懂Netty发送数…

【HarmonyOS Next之旅】基于ArkTS开发(三) -> 兼容JS的类Web开发(七) -> JS动画(二)

目录 1 -> 动画动效 1.1 -> 创建动画对象 1.2 -> 添加动画事件和调用接口 2 -> 动画帧 2.1 -> 请求动画帧 2.2 -> 取消动画帧 1 -> 动画动效 通过设置插值器来实现动画效果。 说明 从API Version 6 开始支持。 1.1 -> 创建动画对象 通过cre…

LINUX下的tcp协议

TCP 1. 面向数据流&#xff08;流式套接字&#xff09; 2. 建立连接 3. 安全可靠的传输协议 应用场景&#xff1a; HTTP, MQTT, FTP 三次握手&#xff1a;TCP建立连接时&#xff0c;需要进行三次握手&#xff0c;确保收发数据前&#xff0c;双方都已准备就绪。 四次挥…

Handy Multi Agent—task1:CAMEL环境配置及你的第一个Agent

目录 1.1 获取CAMEL 1.1.1 通过 PyPI 安装 1.1.2 通过源码安装 1.1.2.1 使用 Poetry 工具从源码安装 1.1.2.2 使用Conda和Pip从源码安装 1.2.2 使用API调用模型 1.2.2.1 使用语言模型 1.2.2.2 使用多模态模型 1.2.2.3 视频理解 1.2.2.4 作业1 1.2.2.5 作业2 1.1 获取…

CSS元素层叠顺序规则

CSS元素层叠顺序规则 看图说话总结: background/borderz-index(<0)blockfloatinline/inline-blockz-index(0,auto)z-index (>0)

微服务全局ID方案汇总

自增id 对于大多数系统来说&#xff0c;使用mysql的自增id当作主键再最合适不过了。在数据库层面就可以获取一个顺序的、唯一的、空间占用少的id。 自增id需要是 int、bigint这些整数类型&#xff0c;uint 支持 40 亿的数据量&#xff0c;bigint unsign&#xff08;0 &#x…