websocket在libevent的应用

websocket在libevent的应用 刘兵 2022-08-26 16:41:45 3203

万物互联,离不开设备和互联网打交道。互联网的服务器一般采用http或https通讯,既节省端口号资源,能够容纳更多连接接入,又应用广泛和成熟。

但是涉及到实时通讯,双端通讯,http就明显力不从心了,并且http每次的header占用几十上百的字节,当大量数据交互式传输时,占用带宽就明显了。为此,websocket横空出世。

websocket本身是长连接,无论是服务器和客户端,都能够主动询问或发送数据(不像http,只能客户端主动请求时,服务器才能在响应里面加上询问的约定)。websocket基于数据包的形式传输数据(不像tcp的数据流,无头无尾),每次传输一包数据,数据包大小从0到16M都行,并且包的封装结构简单,包头很小,占用空间小。

这种通讯和UDP比较,他是基于TCP的连接,数据能够可靠传输到对方,UDP可能会丢包,和TCP相比,websocket是数据包,tcp是数据流,tcp收到数据时还需要设计流程重新封包拆包。

说实话,TCP基础上的封包拆包,有点工作量而已,谁都会,websocket本身的技术也没什么大不了的。

但是他是一个主流软件厂商共同认可的标准,别人的软件都天生支持了该协议,你按标准做,就容易接入,重要的词语说三遍:标准,标准,标准!

关于websocket本身的介绍不多说了,他就是采用标准的http或https连接,在http头里面统一约定后,客户端和服务器同时进入长连接模式,按照标准进行封包解包发送接收,一直到断开连接为止。就算路由器或网关禁止了很多未用端口,也不会禁止80端口或443端口,websocket天生的能够在各种受限的网络环境正常使用和通讯。

如果你水平足够高,可以用socket函数自己写一个http头的解析,然后按照约定进入长连接,再用封包解包函数传输数据,啥事没有,只是要维护一个(或一堆)连接而已。

libevent已经帮你封装好了这些socket库函数,并且考虑可在linux/windows下大海量并发,直接用libevent,调用几个函数,传递几个参数,就能够写出兼容性很高的跨平台(须重编译)的软件,屏弃了你处理socket遇到的各种问题。要知道,写一个socket通讯程序很容易不过,也就是十分钟八分钟的事,编译一下就能成功运行,像模像样的通讯收发,但是后期的调试,找BUG,看文档,换了一个应用场景就要不断调整处理调用顺序、时间、参数等(场景的适用性),不是短时间内能够完成的事,就算你花了很多天,在各种环境下都稳定可靠,用到下一个类似的项目,你仍需要再重复上述过程,你之前的项目再隔三差五暴雷,弄到头昏脑涨疲于应付。libevent用熟之后帮你解决这些问题,TCP、UDP、DNS、HTTP、HTTPS一并解决,高并发、多线程没问题。

libevent虽然很完善很稳定,但是libevent本身不支持websocket,让需要websocket应用场景的时候捉襟见肘。网上有人修改了libevent代码,实现了websocket通讯。但是我认为不是一个好的方法,因为各种的应用场景下,libevent有时候要升级版本啥的,改来改去会弄乱兼容性,再说libevent每个版本的代码都是千锤百炼久经考验,在里面插入代码带来了不确定性。如果发现有问题,不知道是修改版的libevent问题,还是自己其他代码问题,扩大问题的查找范围。

libevent里面有一个http.c文件,基本上所有的http功能都在这里实现(https只是安全连接而已,代码和http是100%兼容),我通过仔细研读里面的机制,写了一个libws库。

这个库支持websocket客户端和服务器,和http是否带s无关,不改变libevent任何代码(原来编译出来的库或官网上下载的库直接使用),只是在libevent初始化http时设置相应的cb为libws_in_cb即可。

libws的句柄是客户端接入回调(用户自己代码)产生的,用户可以根据传入的http头里面的参数,判断是否允许接入,如果不允许直接返回null即可,如果允许则把接收、发送、关闭的回调丢给回调函数的句柄里面。

一旦主动发送,给出libws句柄就能发送,一旦收到数据包,就在接收回调里面。

客户端更简单,直接调用libws_connect函数,传入接入、接收、发送、断开即可回调即可。

该库利用李libevent里面的标准http功能,屏蔽了超时断开,封装了错误处理,简单接口直接暴露给用户使用。

我已经在视频流的互联网传输上应用了该库,服务器和客户端都使用这个库。

有需要的可以下载我上传的资料。

函数如下:

1. 发送数据

int libws_send(struct libws_tpws, uint8_tpdata, size_t size, uint8_t op);

参数1:pws,libws句柄,客户端由libws_connect创建,服务器由set_new_ws里面的用户回调函数创建;

参数2:pdata,数据指针;

参数3:size,数据长度;

参数4:op,操作码,一般选LIBWS_OP_BINARY或LIBWS_OP_TEXT,也可以选LIBWS_OP_PING或LIBWS_OP_PONG

返回值:-1,libws句柄无效,-2数据为空;-3数据长度为0,-4未连接,-5ws未完成握手。

2. 客户端发起连接

目前暂时未实现https连接,待后续更新加上HTTPS的支持。

struct libws_t libws_connect(struct event_base base,

                           const char *url,

                           struct evkeyvalq *exheader,

                           libws_data rd, libws_conn wr, libws_conn con,libws_disconn clo);

参数1:base,libevent的句柄,底层操作由libevent的该base实现;

参数2:url,服务器的地址,也可以指定端口号,IP地址或URL都行,指定路径或不指定路径也行;

参数3:附加http头,用户可以附加自己的http头上去,用法:

struct evkeyvalq hd;

TAILQ_INIT(&hd);

evhttp_add_header(&hd, "Session", tmp->sess);

...

libws_connect(...);

evhttp_clear_headers(&hd);

参数4567:不多讲了,收、发、接入、断开的回调,自己看回调参数即可。

返回值:libws句柄,后面用这个句柄进行主动发送数据就行了。

3. 初始化

void init_libws();

初始化libws的各变量。

4. 销毁

void destory_libws();

在程序退出或重新启动时,销毁变量和释放内存。

5. 服务器接入回调

void set_new_ws(new_conn_cb);

当客户端接入时,调用该回调函数,返回libws句柄,服务器就可以用返回的libws句柄发送数据给客户端。

6. 轮询维护

void libws_poll();

放在定时器里面,每秒钟调用一次就够了,30秒如果没有数据交互时,主动断开连接,销毁句柄。

声明:本文内容由易百纳平台入驻作者撰写,文章观点仅代表作者本人,不代表易百纳立场。如有内容侵权或者其他问题,请联系本站进行删除。
刘兵
红包 2 收藏 评论 打赏
评论
2个
内容存在敏感词
手气红包
  • 刘兵 2022-09-26 08:46:04
    回复
    libws_poll只是libws的一个函数而已,用户定时调用,用于维护libws的连接,不是系统poll函数。
  • hpj 2022-09-24 12:02:22
    回复
    poll 以前都是做大规模并发和游 戏开发才用到
相关专栏
置顶时间设置
结束时间
删除原因
  • 广告/SPAM
  • 恶意灌水
  • 违规内容
  • 文不对题
  • 重复发帖
打赏作者
易百纳技术社区
刘兵
您的支持将鼓励我继续创作!
打赏金额:
¥1易百纳技术社区
¥5易百纳技术社区
¥10易百纳技术社区
¥50易百纳技术社区
¥100易百纳技术社区
支付方式:
微信支付
支付宝支付
易百纳技术社区微信支付
易百纳技术社区
打赏成功!

感谢您的打赏,如若您也想被打赏,可前往 发表专栏 哦~

举报反馈

举报类型

  • 内容涉黄/赌/毒
  • 内容侵权/抄袭
  • 政治相关
  • 涉嫌广告
  • 侮辱谩骂
  • 其他

详细说明

审核成功

发布时间设置
发布时间:
是否关联周任务-专栏模块

审核失败

失败原因
备注
拼手气红包 红包规则
祝福语
恭喜发财,大吉大利!
红包金额
红包最小金额不能低于5元
红包数量
红包数量范围10~50个
余额支付
当前余额:
可前往问答、专栏板块获取收益 去获取
取 消 确 定

小包子的红包

恭喜发财,大吉大利

已领取20/40,共1.6元 红包规则

    易百纳技术社区