Skynet.socket 函数族使用详解

在这里插入图片描述

目录

  • Skynet.socket 函数族使用详解
  • 核心功能分类
  • 一、TCP 连接管理
    • 1. 监听端口
    • 2. 建立连接
    • 3. 关闭连接
  • 二、数据读写操作
    • 1. 阻塞式读取
    • 2. 写入数据
      • 2.1 `socket.write(fd, data)` 的返回值
      • 2.2 示例代码
      • 2.3 关键注意事项
      • 2.4 与其他函数的区别
      • 2.5 底层原理
      • 2.6 总结
  • 三、UDP 处理
    • 1. 创建 UDP 句柄
    • 2. 发送 UDP 数据
  • 四、高级控制与监控
    • 1. 缓冲区过载警告
    • 2. 域名解析
  • 五、SocketChannel 封装
    • 1. 创建 Channel 对象
    • 2. 发送请求
  • 六、最佳实践与注意事项
  • 总结

Skynet.socket 函数族使用详解

Skynet 的 skynet.socket 模块提供了 TCP/UDP 网络通信的核心 API,结合协程机制实现了阻塞式调用模型,简化了异步网络编程。本文详细解析其核心函数、使用场景及最佳实践。


核心功能分类

  1. TCP 连接管理(监听、连接、关闭)
  2. 数据读写(阻塞式读写、分包处理)
  3. UDP 支持(数据包收发、地址管理)
  4. 高级控制(缓冲区警告、域名解析、过载处理)

一、TCP 连接管理

1. 监听端口

local socket = require "skynet.socket"-- 启动 TCP 服务器
skynet.start(function()local listen_fd = socket.listen("0.0.0.0", 8888) -- 监听 8888 端口socket.start(listen_fd, function(client_fd, addr)-- 新连接回调,处理客户端请求socket.start(client_fd)-- ... 处理数据逻辑end)
end)
  • socket.listen(host, port [, backlog])
    返回监听套接字的文件描述符 listen_fd
    backlog:等待连接队列的最大长度(可选,默认 SOMAXCONN)。

2. 建立连接

local client_fd = socket.open("127.0.0.1", 6379) -- 连接 Redis
if client_fd thensocket.start(client_fd)socket.write(client_fd, "PING\r\n")
end
  • socket.open(host, port)
    同步阻塞连接目标地址,返回客户端套接字 client_fd

3. 关闭连接

socket.close(client_fd)  -- 安全关闭,等待未完成读写
socket.close_fd(client_fd) -- 强制立即关闭(慎用)
socket.shutdown(client_fd) -- 强制关闭(适用于 __gc 元方法)
  • 区别
    • close:等待其他协程完成读写后关闭。
    • close_fd/shutdown:直接关闭,可能导致未处理数据丢失。

二、数据读写操作

1. 阻塞式读取

-- 读取固定字节
local data, partial = socket.read(client_fd, 1024) -- 读 1024 字节
if data thenprint("完整数据:", data)
elseprint("部分数据:", partial) -- 连接已关闭
end-- 读取一行(默认以 \n 分割)
local line = socket.readline(client_fd, "\r\n") -- 自定义分隔符
  • socket.read(fd, sz)
    • sznil 时读取尽可能多的数据(至少 1 字节)。
    • 返回完整数据或 false + 已读部分数据(连接关闭时)。

2. 写入数据

socket.write(client_fd, "Hello Skynet!\r\n") -- 高优先级写入
socket.lwrite(client_fd, "Low priority data\r\n") -- 低优先级写入
  • 优先级区别
    • write:数据进入高优先级队列,优先发送。
    • lwrite:数据进入低优先级队列,高优先级队列为空时发送。
      在 Skynet 框架中,socket.write 方法的返回值取决于数据是否成功写入内核的发送缓冲区。以下是具体说明:

2.1 socket.write(fd, data) 的返回值

  1. 成功时

    • 返回 true,表示数据已成功加入内核的发送队列,不保证对端已接收
    • 注意:返回值仅表示数据成功提交到操作系统的网络协议栈,实际网络传输是异步的。
  2. 失败时

    • 返回 nil + 错误信息(如 "closed" 表示连接已关闭)。
    • 常见错误:
      • "closed": 连接已关闭。
      • "timeout": 发送超时(需结合 socketdriver.settimeout 设置)。
      • "error": 其他底层错误。

2.2 示例代码

local skynet = require "skynet"
local socket = require "skynet.socket"local fd = ...  -- 假设 fd 是已建立的客户端连接-- 尝试发送数据
local ok, err = socket.write(fd, "Hello World")
if not ok thenskynet.error("Send failed:", err)socket.close(fd)  -- 关闭失效连接
end

2.3 关键注意事项

  1. 异步发送socket.write 是非阻塞的,数据可能仍在发送队列中未实际传输。
  2. 流量控制:若发送速度超过网络带宽或对端接收速度,可能导致缓冲区积压,最终触发错误。
  3. 错误处理:务必检查返回值,及时关闭失效的 fd,避免资源泄漏。
  4. 大包分片:单次写入数据过大可能被系统拆分,需结合业务逻辑处理完整性(如添加长度头)。

2.4 与其他函数的区别

  • socket.send:与 socket.write 行为一致,两者是别名关系。
  • socket.lwrite:专用于发送 Lua 字符串(内部优化),行为相同。

2.5 底层原理

Skynet 的 socket.write 最终调用操作系统的 send 系统调用,但通过非阻塞模式封装。若内核发送缓冲区已满,数据会排队等待,此时返回 true;若连接已异常(如对端关闭),则直接返回错误。


2.6 总结

  • 返回值意义true 表示数据提交成功,nil + err 表示失败。
  • 必须处理错误:尤其要捕获 "closed" 错误,及时清理连接状态。
  • 性能影响:高频发送时建议结合 socketdriver.setqueue_max 控制缓冲区大小,避免内存暴涨。

三、UDP 处理

1. 创建 UDP 句柄

local udp_fd = socket.udp(function(data, from)print("收到 UDP 数据:", data, "来源:", socket.udp_address(from))
end, "0.0.0.0", 9999) -- 绑定 9999 端口
  • socket.udp(callback [, host, port])
    创建 UDP 句柄并绑定回调,收到数据时触发 callback(data, from)

2. 发送 UDP 数据

socket.sendto(udp_fd, from_address, "ACK") -- 发送到指定地址
socket.write(udp_fd, "Ping") -- 若已设置默认地址,直接写入
  • socket.sendto(fd, from, data)
    from 为接收到的来源地址字符串,不可手动构造。

四、高级控制与监控

1. 缓冲区过载警告

socket.warning(client_fd, function(fd, size)if size > 0 thenprint("警告:待发数据超过", size, "KB")elseprint("缓冲区已清空")end
end)
  • socket.warning(fd, callback)
    监控待发数据量,超过 1MB 触发回调(默认每超 64KB 打印错误日志)。

2. 域名解析

local dns = require "skynet.dns"
dns.server("8.8.8.8") -- 设置 DNS 服务器
local ip, all_ips = dns.resolve("www.example.com") -- 解析域名
  • dns.resolve(name [, ipv6])
    返回解析到的 IP 地址及所有 IP 列表,避免阻塞 socket 线程。

五、SocketChannel 封装

1. 创建 Channel 对象

local sc = require "skynet.socketchannel"
local channel = sc.channel {host = "127.0.0.1",port = 6379,response = function(sock)return true, sock:readline("\r\n") -- 解析 Redis 响应end,
}
  • 模式选择
    • 提供 response 函数则进入 Session 模式(如 MongoDB)。
    • 否则为 请求-回应模式(如 Redis)。

2. 发送请求

local resp = channel:request("PING\r\n") -- 请求并等待响应
local resp2 = channel:request("GET key\r\n", function(sock)return true, sock:read(5) -- 自定义响应解析
end)
  • channel:request(req [, response | session])
    发送请求并自动匹配响应,支持自定义解析逻辑。

六、最佳实践与注意事项

  1. 连接生命周期管理

    • 使用 socket.close 确保安全关闭。
    • 避免在 __gc 中使用阻塞操作,优先用 shutdown
  2. 协程调度优化

    • 高频读写时,合理使用 socket.lwrite 避免阻塞关键数据。
    • 结合 skynet.fork 处理并发请求。
  3. 错误处理

    • 所有读写操作需包裹在 pcall 中捕获异常。
    • UDP 需处理乱序和丢包,不可依赖时序。
  4. 性能监控

    • 使用 socket.warning 监控缓冲区,防止内存溢出。
    • 避免频繁 DNS 查询,通过缓存或独立服务处理。

总结

skynet.socket 通过协程化阻塞 API 简化了网络编程复杂度,结合 socketchannel 可高效处理复杂协议。开发者需注意:

  • 连接安全性:合理关闭连接,避免资源泄漏。
  • 协议适配:根据场景选择基础 API 或高级封装。
  • 性能调优:监控缓冲区,平衡吞吐量与内存消耗。

通过阅读 lualib/socket.lua 和参考 service/gate.lua,可深入理解底层实现机制。

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

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

相关文章

Unity Addressables资源生命周期自动化监控技术详解

一、Addressables资源生命周期管理痛点 1. 常见资源泄漏场景 泄漏类型典型表现检测难度隐式引用泄漏脚本持有AssetReference未释放高异步操作未处理AsyncOperationHandle未释放中循环依赖泄漏资源相互引用无法释放极高事件订阅泄漏未取消事件监听导致对象保留高 2. 传统管理…

aws(学习笔记第三十八课) codepipeline-build-deploy-github-manual

文章目录 aws(学习笔记第三十八课) codepipeline-build-deploy-github-manual学习内容:1. 整体架构1.1 代码链接1.2 全体处理架构2. 代码分析2.1 创建`ImageRepo`,并设定给`FargateTaskDef`2.2 创建`CodeBuild project`2.3 对`CodeBuild project`赋予权限(`ECR`的`image rep…

在windows服务器使用Nginx反向代理云端的python实现的web应用

近日得闲,计划将之前写过的一些小桌面程序搬到云服务器上方便随时随地使用,同时也学习一些基本的网站开发和搭建知识,于是在AI的帮助下,基于niceguifastapi非常快捷地搞出来了一个前后端一体的网站程序,放在云服务器上…

全球贸易战火重燃:50%关税如何绞杀跨境电商低价模式?

一、政策高压:美国对华贸易战升级路线图 2024年5月,美国国会《数字贸易壁垒法案》草案曝光,标志着中美贸易博弈进入新阶段: • 关税武器精准打击:成衣、消费电子、小家电税率拟从10-25%跃升至50% • 监管范围扩大&…

0411 | 软考高项笔记:项目立项

在软考的项目管理知识体系中,技术可行性和经济可行性是项目立项阶段非常重要的两个分析维度。以下是对这两个考点的详细解释和记忆方法: 技术可行性分析 定义: 技术可行性分析是评估项目在现有技术条件和资源下是否能够成功实施。它主要回答…

二分查找3:69. x 的平方根

链接:69. x 的平方根 - 力扣(LeetCode) 题解: 本题本质是二分查找右端点 x的算数平方根一定在1 ~ x 区间内,在1 ~ x区间内查找一个数num,num^2x,但实际上num不一定是整数,所以是n…

oracle大师认证证书有用吗

专业能力的高度认可:OCM 是 Oracle认证的最高级别,是对数据库从业人员技术、知识和操作技能的最高级认可,也是 IT 界顶级认证之一。它表明持证者具备处理关键业务数据库系统和应用的能力,能够解决最困难的技术难题和最复杂的系统故…

InnoDB 如何解决幻读:深入解析与 Java 实践

在数据库事务管理中,幻读(Phantom Read)是并发操作中常见的问题,可能导致数据一致性异常。MySQL 的 InnoDB 存储引擎通过其事务隔离机制和多版本并发控制(MVCC),有效解决了幻读问题。作为 Java …

【AI编程技术爆发:从辅助工具到生产力革命】

目录 前言:技术背景与价值当前技术痛点解决方案概述目标读者说明 一、技术原理剖析核心概念图解关键技术模块技术选型对比 二、实战演示环境配置要求核心代码实现运行结果验证 三、性能对比测试方法论量化数据对比(2023年数据)结果分析 四、最…

ICRA-2025 | 视觉预测助力机器人自主导航!NavigateDiff:视觉引导的零样本导航助理

论文:Yiran Qin 1 , 2 ^{1,2} 1,2, Ao Sun 2 ^{2} 2, Yuze Hong 2 ^{2} 2, Benyou Wang 2 ^{2} 2, Ruimao Zhang 1 ^{1} 1单位: 1 ^{1} 1中山大学, 2 ^{2} 2香港中文大学深圳校区论文标题:NavigateDiff: Visual Predictors are Ze…

【ESP32S3】GATT Server service table传送数据到调试助手

前言 在初步学习esp32蓝牙的过程中,借鉴了官方的GATT Server Service Table Example,可以在readme中看到,此demo是采用低功耗蓝牙的通用属性服务器来创建订阅服务和特性。如果你接触过MQTT,你会发现GATT Server这一特性和MQTT的订…

DeepSeek :中国 AI 如何用 “小米加步枪” 逆袭硅谷

2025 年春节前夕,人工智能领域诞生了一项重大成果 ——DeepSeek 发布DeepSeek - R1 大模型。这一模型迅速引发广泛关注,在苹果 AppStore 中国区免费榜登顶。 DeepSeek 采用开源策略,依据宽松的 MIT 许可证,公开了模型权重、训练方…

关税扰动下市场波动,如何寻找确定性的长期之锚?

近期的关税纷争,扰动全球资本市场下行。A股市场一度大幅下跌。但随着各大主力下场,有关部委发布有关有力措施,A股逐步稳住阵脚。 4月8日至4月10日,大盘指数连续3天上涨,上涨120多点,展现出较强的抵御关税壁…

NeuroImage:膝关节炎如何影响大脑?静态与动态功能网络变化全解析

膝骨关节炎(KOA)是导致老年人活动受限和残疾的主要原因之一。这种疾病不仅引起关节疼痛,还会显著影响患者的生活质量。然而,目前对于KOA患者大脑功能网络的异常变化及其与临床症状之间的关系尚不清楚。 2024年4月10日,…

【KWDB 创作者计划】KWDB 数据库全维度解析手册

——从原理到实践,构建下一代数据基础设施 ​第一章:KWDB 设计哲学与技术全景 1.1 为什么需要 KWDB? 在数据爆炸与业务场景碎片化的今天,传统数据库面临三大挑战:​扩展性瓶颈​(单机性能天花板&#xff…

一个批量文件Dos2Unix程序(Microsoft Store,开源)

这个程序可以把整个目录的文本文件改成UNIX格式,源码是用C#写的。 目录 一、从Microsoft Store安装 二、从github获取源码 三、功能介绍 3.1 运行 3.2 浏览 3.3 转换 3.4 转换(无列表) 3.5 取消 3.6 帮助 四、源码解读 五、讨论和…

std::string` 类

以下是对 std::string 类中 修改操作 和 字符串操作 的示例代码&#xff0c;帮助你更好地理解这些函数的使用&#xff1a; 5. 修改操作 (1) operator 用于追加字符串、C 风格字符串或字符。 #include <iostream> #include <string>int main() {std::string str …

《Spring Boot+策略模式:企业级度假订单Excel导入系统的架构演进与技术实现》

前言 在数字化时代背景下&#xff0c;订单管理系统的高效性与灵活性成为企业竞争力的核心要素。本文档详细剖析了一个基于 策略模式 的度假订单导入系统&#xff0c;通过分层架构设计实现了多源异构数据的标准化处理。系统以 Spring Boot 为核心框架&#xff0c;结合 MyBatis …

SSRF漏洞公开报告分析

文章目录 1. SSRF | 获取元数据 | 账户接管2. AppStore | 版本上传表单 | Blind SSRF3. HOST SSRF一、为什么HOST修改不会影响正常访问二、案例 4. Turbonomic 的 终端节点 | SSRF 获取元密钥一、介绍二、漏洞分析 5. POST | Blind SSRF6. CVE-2024-40898利用 | SSRF 泄露 NTL…

告别 ifconfig:为什么现代 Linux 系统推荐使用 ip 命令

告别 ifconfig&#xff1a;为什么现代 Linux 系统推荐使用 ip 命令 ifconfig 指令已经被视为过时的工具&#xff0c;不再是查看和配置网络接口的推荐方式。 与 netstat 被 ss 替代类似。 本文简要介绍 ip addr 命令的使用 简介ip ifconfig 属于 net-tools 包&#xff0c;这个…