经过多次代码测试,总结如下:
bufferevent_socket_connect
返回0,不代表和服务器连接成功,返回-1一定是连接失败(简单看了下源码,的确大部分情况都是返回0,包括连接被拒绝等)- 网线未插(wifi未连接),服务器没开,
bufferevent_socket_connect
立即返回0,但在后台继续请求连接(前提socket已被设置成非阻塞),若无进一步操作,将在130秒后,报错:110-Connection timed out
- 在上述状态下,若先插网线,再开服务器,几秒之后,可以成功建立连接,也有可能报错:
113-No route to host
- 在上述状态下,若先开服务器,再插网线,十几秒之后,报错:
113-No route to host
- 网络连接已正常,服务器没开,立即报错:
111-Connection refused
- 网络连接正常状态下,若服务器关闭,则
BEV_EVENT_EOF
事件触发,客户端可通过该事件确认服务器被关闭 - 上述所有错误都会产生
BEV_EVENT_ERROR
事件,且触发event_cb
回调,客户端可在event_cb
回调函数中处理这些错误信息,包括网络重连,或向HMI显示网络问题,或将这些信息输出到系统日志 bufferevent_free
会关闭套接字(BEV_OPT_CLOSE_ON_FREE
开启情况下),如果该套接字正在进行connect,则会立即结束。不过,测试发现不会立即释放该sockfd,比如刚关闭的套接字sockfd=9,free掉之后,该sockfd关闭,但此时若新建sockfd,则sockfd=10,而不是9.- 通过
socket()
和connect()
创建套接字以及建立连接时,默认是阻塞的,一种处理方法是通过定时器终止connect以避免阻塞,不过该方法对bufferevent_socket_connect
无效(当传入的sockfd是阻塞的时候),SIGALAM
触发了之后,仍继续connect,netstat查看,的确还在SYN_SENT
状态。故需要使用上述第8点方法,若超时未连接上,又无错误返回,直接bufferevent_free
,然后重连 event_base_new
在主线程创建base
,bufferevent_socket_new
在子线程创建bufferevent
监听网口(以及event_new
也在子线程创建event事件进行串口、CAN口监听),此时需开启libevent的多线程支持功能,否则无法将event或bufferevent添加到base。Linux下开启多线程支持需以下三句代码:
evthread_use_pthreads();
base = event_base_new();
evthread_make_base_notifiable(base);
2021-5-16 更新
前几天调试外设时,在一个非正常的,实际不会发生的工况下模拟测试时,发现一个怪异的问题:
event_base_new
在主线程创建,另起一个线程进行bufferevent_socket_new
、bufferevent_socket_connect
,然后等待回调bev_event_cb
执行,检查是否连接成功,此时,如果主线程休眠了,bev_event_cb
貌似不会立即回调,而是等到主线程休眠结束后才回调……
由于时间紧迫,而且libevent这块儿框架基本都写好了,就懒得继续深入测试分析了,先记下来再说,以后有空再研究吧。
2021-8-2 更新
当bufferevent连接成功后,客户端正常发送数据,服务器正常接收,在未开启接收超时的情况下。此时,如果将网线拔出来,客户端和服务器都不会报错(event_cb
不会被回调,因此在event_cb
中写的网络重连逻辑也不会被触发)。bufferevent_write
仍然返回0,也即写入成功(写入发送缓冲区)。
一段时间后,重新插上网线。此时,服务器将接收到一堆数据,该数据为网线拔出来之后,客户端写入发送缓冲区但没有被服务器接收的数据。接收完毕之后,恢复正常通讯
上图中,客户端每秒发送一串字符串“Hello,this is a test for bufferevent_write function!”,中途将网线拔出,一段时间后再插上,接收到一堆字符串后,再次恢复到正常通讯状态。
因此,目前通过设置接收超时(bufferevent_set_timeouts
)来判断网络连接是否正常,若在设定的时间内没有收到服务器发送的数据,则认为网络断开,关闭bufferevent后重连。