OpenResty 从入门到实战
温铭
OpenResty 软件基金会第一任主席,Apache APISIX 项目 VP
20903 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 52 讲
结束语 (1讲)
OpenResty 从入门到实战
15
15
1.0x
00:00/00:00
登录|注册

19 | OpenResty 的核心和精髓:cosocket

TCP 相关的 API 应该如何使用
实际的例子
相关的指令和 API
学习了cosocket 的基本概念
不直接关闭 socket,而是放入连接池中
receive接收指定大小的内容
分别设置超时时间
lua_socket_log_errors
lua_socket_keepalive_timeout
lua_socket_pool_size
lua_socket_buffer_size
lua_socket_read_timeout
lua_socket_send_lowat
lua_socket_send_timeout
lua_socket_connect_timeout
init_worker_by_lua*
init_by_lua*
body_filter_by_lua*
header_filter_by_lua*
log_by_lua*
set_by_lua*
ssl_session_fetch_by_lua*
ssl_certificate_by_lua*
ngx.timer.*
content_by_lua*
access_by_lua*
rewrite_by_lua*
关闭连接:tcpsock:close
连接池:tcpsock:setkeepalive
接受数据:tcpsock:receive、tcpsock:receiveany 和 tcpsock:receiveuntil
发送数据:tcpsock:send
建立连接:tcpsock:connect
设置超时:tcpsock:settimeout 和 tcpsock:settimeouts
创建对象:ngx.socket.tcp
网络套接字
协程
总结
调整示例
lua_socket_ 开头的 Nginx 指令
限制
API 使用的上下文
cosocket API 和指令简介
cosocket
OpenResty 的核心和精髓:cosocket

该思维导图由 AI 生成,仅供参考

你好,我是温铭,今天我们来学习下 OpenResty 中的核心技术:cosocket。
其实在前面的课程中,我们就已经多次提到过它了,cosocket 是各种 lua-resty-* 非阻塞库的基础,没有 cosocket,开发者就无法用 Lua 来快速连接各种外部的网络服务。
在早期的 OpenResty 版本中,如果你想要去与 Redis、memcached 这些服务交互的话,需要使用 redis2-nginx-moduleredis-nginx-modulememc-nginx-module这些 C 模块. 这些模块至今仍然在 OpenResty 的发行包中。
不过,cosocket 功能加入以后,它们都已经被 lua-resty-redislua-resty-memcached 替代,基本上没人再去使用 C 模块连接外部服务了。

什么是 cosocket?

那究竟什么是 cosocket 呢?事实上,cosocket 是 OpenResty 中的专有名词,是把协程和网络套接字的英文拼在一起形成的,即 cosocket = coroutine + socket。所以,你可以把 cosocket 翻译为“协程套接字”。
cosocket 不仅需要 Lua 协程特性的支持,也需要 Nginx 中非常重要的事件机制的支持,这两者结合在一起,最终实现了非阻塞网络 I/O。另外,cosocket 支持 TCP、UDP 和 Unix Domain Socket。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

OpenResty 中的核心技术 cosocket 结合了协程和网络套接字,实现了非阻塞网络 I/O。该技术提供了一系列功能,包括创建对象、设置超时、建立连接、发送和接收数据、连接池管理等。本文通过示例代码演示了如何使用这些 API 进行网络通信,以及如何设置超时时间、接收指定大小的数据和放入连接池。此外,还介绍了与这些 API 相关的 Nginx 指令,以及一些注意事项,如 API 的使用上下文和连接池的注意事项。通过本文,读者可以快速了解 OpenResty 中 cosocket 的核心概念和使用方法,以及其在实际开发中的应用场景。文章还提出了两个作业题,引发读者思考和交流。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《OpenResty 从入门到实战》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(13)

  • 最新
  • 精选
  • HelloBug
    问题一:将表格利用cjson进行序列化之后发送 问题二:通过设置定时器,在不能使用cosocket的阶段使用

    作者回复: 第二个答案是对的。第一个确实是可以的,但并非最好的方案,send 函数不仅支持字符串,还支持 table,这也是隐藏的优化点。

    2019-07-08
    2
    8
  • 小超人
    有个真实需求: client --密文--> Openresty解密 --明文--> server client <--密文-- Openresty加密 <--明文-- server 1. 这是TCP应用,send/recv不一定是一对儿,比如有个大请求,client需要send 10次以后再收; 2. Openresty知道client发过来的密文格式,带total_len,可以正常receive(total_len)就可以了; 3. 【问题】Openresty不知道业务数据格式,在receive上游服务器时,遇到两个问题: *3.1* 不知道什么时候receive,如1.描述,Openresty将明文转发至server时,server不一定有返回数据; *3.2*如果来了数据,不知道该收多少,因为不知道业务数据的格式。 【我现在的做法是】 1. Openresty receive server那一侧,设置了一个buf_len,和一个较小的超时,比如200ms; 2. Openresty每转发一次数据到server,都尝试receive一下server,如果超时,不报错不返回;如果receive到数据了,就加密返回后再循环receive,直到无数据(超时); 这样虽然解决了问题,但是性能太差了,在openresty---server那一侧,至少要receive超时一次,才能知道收完数据了。 【请问】有更好的解决办法吗?

    作者回复: 我理解了你的问题,尝试回答下,不一定准确: 1. client 会传上来 total_len,那么 OpenResty 就能计算出来第几次 send 是最后一次。在最后一次 client send 的数据解密并转发给上游 server 后,开始 receive server。是否可以解决呢? 2. 这个有有些尴尬了,即使OpenResty 不关心数据格式,至少也要知道数据长度或者结束符,这两个的其中一个。不然无法知道何时结束。

    2019-07-13
    3
    2
  • helloworld
    老师: [error] 16239#16239: *5 attempt to send data on a closed socket: u:0000000000000000, c:0000000000000000 客户端每次post数据过来,lua都可以正确的将数据写入redis,但是error.log日志中总是报这个错误。 老师,我没用到redis连接池,我这个应用场景是每隔一段时间post请求往redis写数据,所以没必要使用连接池。关于redis的语句只有下面这些: local redis = require "resty.redis" local red = redis:new() red:set_timemout(2000) -- 2 sec local ip = "127.0.0.1" local port = 6379 local ok, err = red:connect(ip, port) if not ok then ... end ok, err = red:hset(data_time, client, json_encode(data)) if not ok then ... end

    作者回复: 建议在 redis:new() 的时候判断下是否成功。 另外附上 OpenResty 作者给这个错误的排查意见:https://github.com/openresty/lua-resty-redis/issues/27#issuecomment-28166754,自然是更加权威的。

    2019-07-12
    2
    1
  • helloworld
    老师,是不是不论在哪个阶段运行ngx.say('hello'),都会在执行完本阶段剩余代码后直接响应给客户端,不会继续执行其他阶段了。我测试是这样的。

    作者回复: 并不是,你可以看下它的执行阶段的顺序图:https://github.com/moonbingbing/openresty-best-practices/blob/master/images/openresty_phases.png,你可以做这个测试,在 content 里面 ngx.say,然后在 log 或者 body filter 阶段打印下日志试试。

    2019-07-08
    2
    1
  • wusiration
    问题一:将table通过cjson序列化,但是看到老师有说send函数支持table,查阅api文档有说The input argument data can either be a Lua string or a (nested) Lua table holding string fragments.In case of table arguments, this method will copy all the string elements piece by piece to the underlying Nginx socket send buffers, which is usually optimal than doing string concatenation operations on the Lua land. 问题二:通过shared dict进行数据传递

    作者回复: 接收 table 而非字符串,是 OpenResty Lua API 的一个重要的优化点。 通过shared dict进行数据传递,这个我不是很明白,这个是如何绕过限制的呢?

    2019-07-13
    2
  • helloworld
    [error] 16239#16239: *5 attempt to send data on a closed socket: u:0000000000000000, c:0000000000000000 客户端每次post数据过来,lua都可以正确的将数据写入redis,但是error.log日志中总是报这个错误,求解。

    作者回复: 是否使用了redis 的连接池?猜测连接池里面有不正常的连接,但是被复用了。可以确认下放进连接池之前,代码中是否判断了连接是否正常?

    2019-07-08
  • HelloBug
    文中利用cosocket将TCP请求发送到www.baidu.com的例子,我运行了一下包含头域Host:www.baidu.com和不包含该头域的请求,抓包来看,也确实是一个包含Host头域,一个不包含,两个请求都能得到百度的200应答。有一个问题是,我在本地使用proxy,然后转upstream时,如果不指定请求头域为请求到的域名的话,就不能得到正确的应答。这里是我写的关于这个问题的博客链接:https://blog.csdn.net/u013139008/article/details/94732537 介绍这个问题。老师,你知道这里必须要指定头域是www.baidu.com的原因吗?

    作者回复: 一般来说,一个 ip 上可能会运行多个网站,所以会通过 server name 来做区分,比如 Nginx 中的 server 这个指令。如果没有设置 proxy_set_header Host "www.baidu.com"; 的话,在路由的时候就可能会找不到 server。

    2019-07-08
    2
  • swimming
    老师,有个实际需求,需要在header filter阶段调用http接口,后续的处理依赖这次调用的返回结果,这种情况使用timer跳过无法满足需求,因为不能保证后续处理时timer已经调用完毕返回结果了。请问这种情况有处理方案吗?
    2020-11-14
    1
    1
  • Leo
    真是用心良苦,我在openresty的github介绍页上,看见了英文版的介绍,真挺不容易的,为了推广,等于把英文版的介绍,做了拣选之后做了整理翻译。谢谢了,我也在努力补英语,中国体制教育的受害者,我是学俄语的,初中被分到了俄语班,没机会选择,并且家里也没去争取过。没办法靠自己吧,不过真的挺无语的,我培训的机构受双减政策倒闭了,你想往出走,就要打断你的腿,我们的民族进步还有希望么
    2021-12-08
  • 金黄十月
    温老师:问一下,为什么使用ngx.socket.tcp连接本机IP (192.168.0.2)的服务,总是返回”Connection refused“错误,使用python去连接本机的服务,或者使用telnet 192.168.0.2却可以成功;使用ngx.socket.tcp连接本机IP (192.168.0.6)是成功的。感觉是openresty的问题。比如连接池返回的socket有问题还是其他原因?有没有什么好建议?
    2021-08-16
收起评论
显示
设置
留言
13
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部