19 | OpenResty 的核心和精髓:cosocket
该思维导图由 AI 生成,仅供参考
什么是 cosocket?
- 深入了解
- 翻译
- 解释
- 总结
OpenResty 中的核心技术 cosocket 结合了协程和网络套接字,实现了非阻塞网络 I/O。该技术提供了一系列功能,包括创建对象、设置超时、建立连接、发送和接收数据、连接池管理等。本文通过示例代码演示了如何使用这些 API 进行网络通信,以及如何设置超时时间、接收指定大小的数据和放入连接池。此外,还介绍了与这些 API 相关的 Nginx 指令,以及一些注意事项,如 API 的使用上下文和连接池的注意事项。通过本文,读者可以快速了解 OpenResty 中 cosocket 的核心概念和使用方法,以及其在实际开发中的应用场景。文章还提出了两个作业题,引发读者思考和交流。
《OpenResty 从入门到实战》,新⼈⾸单¥59
全部留言(13)
- 最新
- 精选
- HelloBug问题一:将表格利用cjson进行序列化之后发送 问题二:通过设置定时器,在不能使用cosocket的阶段使用
作者回复: 第二个答案是对的。第一个确实是可以的,但并非最好的方案,send 函数不仅支持字符串,还支持 table,这也是隐藏的优化点。
2019-07-0828 - 小超人有个真实需求: 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-1332 - 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-1221 - 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-0821 - 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-132 - 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-082 - swimming老师,有个实际需求,需要在header filter阶段调用http接口,后续的处理依赖这次调用的返回结果,这种情况使用timer跳过无法满足需求,因为不能保证后续处理时timer已经调用完毕返回结果了。请问这种情况有处理方案吗?2020-11-1411
- 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