websocket在libevent的应用-websocket socket

万物互联,离不开设备和互联网打交道。互联网的服务器一般采用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_t*pws, uint8_t*pdata, 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秒如果没有数据交互时,主动断开连接,销毁句柄。

免责声明:文章内容来自互联网,本站不对其真实性负责,也不承担任何法律责任,如有侵权等情况,请与本站联系删除。
转载请注明出处:websocket在libevent的应用-websocket socket https://www.yhzz.com.cn/a/9846.html

上一篇 2023-04-20
下一篇 2023-04-20

相关推荐

联系云恒

在线留言: 我要留言
客服热线:400-600-0310
工作时间:周一至周六,08:30-17:30,节假日休息。