websocket在libevent的应用
万物互联,离不开设备和互联网打交道。互联网的服务器一般采用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秒如果没有数据交互时,主动断开连接,销毁句柄。
- 分享
- 举报
-
刘兵 2022-09-26 08:46:04回复 举报libws_poll只是libws的一个函数而已,用户定时调用,用于维护libws的连接,不是系统poll函数。
-
hpj 2022-09-24 12:02:22回复 举报poll 以前都是做大规模并发和游 戏开发才用到
-
浏览量:4176次2021-01-26 18:09:03
-
浏览量:2033次2019-07-15 16:16:15
-
浏览量:1397次2019-07-16 17:04:48
-
浏览量:17605次2022-01-16 09:00:14
-
浏览量:2221次2019-09-10 17:27:20
-
浏览量:2666次2021-05-20 18:37:27
-
浏览量:10829次2021-06-25 15:00:55
-
浏览量:1614次2022-12-17 11:50:11
-
浏览量:1388次2024-03-31 22:08:36
-
浏览量:2725次2020-12-16 10:07:26
-
浏览量:123次2023-08-23 08:46:26
-
浏览量:1941次2020-06-24 15:44:51
-
浏览量:1810次2022-12-16 16:27:02
-
浏览量:1976次2019-11-12 17:19:52
-
浏览量:700次2023-08-11 15:16:04
-
浏览量:157次2023-08-30 15:28:02
-
浏览量:7062次2021-07-12 11:03:00
-
浏览量:5043次2021-03-31 17:33:56
-
浏览量:2925次2018-01-30 19:45:14
-
广告/SPAM
-
恶意灌水
-
违规内容
-
文不对题
-
重复发帖
刘兵
感谢您的打赏,如若您也想被打赏,可前往 发表专栏 哦~
举报类型
- 内容涉黄/赌/毒
- 内容侵权/抄袭
- 政治相关
- 涉嫌广告
- 侮辱谩骂
- 其他
详细说明