libwebsockets支持外部eventloop變更


早些年還在使用2.4+版本,現在最新版已經到4.1+,centos 7也使用3.+版本。對於使用外部eventloop相關的接口發生了大的變更。libev也應為早早對iouring支持,4+版本親睞libev而不在是libuv。

首先是接口                                                                                                       

libwebsockets一直以來都支持libuv,libev以及libevent。

在2.4+時候,通過接口函數lws_uv_initloop, lws_ev_initloop以及lws_event_initloop指定使用外部eventloop。           

在3.0.0開始,這三個函數被去掉,取而代之是在lws_context_creation_info結構添加一個新成員foreign_loops,並為options成員添加三個新選項LWS_SERVER_OPTION_LIBUV, LWS_SERVER_OPTION_LIBEV以及LWS_SERVER_OPTION_LIBEVENT, 在lws_create_context時加載plugin的方式。                                                                                           

可以參看下面地址:https://libwebsockets.org/abi/headers_diff/libwebsockets/2.4.2/3.0.0/diff.html 

編譯時,可以選擇動態或靜態兩種plugin方式,yum釋放的libwebsockets使用3.0.1並且只支持libuv的靜態plugin。 對於使用自己編譯的libwebsockets.so動態加載evlib_plugin失敗的情況,因為代碼默認只搜索安裝路徑,如果有需要的話,可以修改lib/core/context.c的dlist,添加"."等相對路徑。         

另外libev好像要變強了?4+后的libwebsockets不再偏向libuv而轉向libev。你會發現,4+的libwebsockets在CMake時候多了兩個檢查,分別是LWS_HAVE_EVBACKEND_LINUXAIO跟LWS_HAVE_EVBACKEND_IOURING,重點是iouring,linux5的東東。libev已經支持了。 

iouring可以參考: https://kkc.github.io/2020/08/19/io-uring/

題目結束。 

==========

libwebsockets使用注意

1。對方的ping,本方pong后會觸發一次PULLOUT,LWS_CALLBACK_CLIENT_WRITEABLE。

2。lws_parse_uri函數設計有問題。第一輸入參數uri,分析后prot,address,path三個輸出參數以const char*指針指向uri字符串對應子字符串的位置,意思是不可以修改輸出的子字符串,但是自己有對輸入參數uri進行了修改,替換'\0'。所以不能用全局只讀區的字符串,還有你的配置字符串或留底的字符串。path有一個缺陷,你要在前面加'/',你又要新建一個字符串。這里可以考慮在拷貝uri多留空間,在path的位置movemem后加'/'。

3。LWS_CALLBACK_WSI_CREATE與描述不同,client端通知對應的協議。而server端因為在ws握手之前不清楚protocol,所以分派到protocol[0]。LWS_CALLBACK_CLIENT_CONNECTION_ERROR,同理。

LWS_CALLBACK_WSI_DESTROY分派到protocol[0]。

LWS_CALLBACK_WSI_CREATE                    = 29,
    /**< outermost (earliest) wsi create notification to protocols[0] */

    LWS_CALLBACK_WSI_DESTROY                = 30,
    /**< outermost (latest) wsi destroy notification to protocols[0] */

4。client流程事件:

a。socket connect成功后,LWS_CALLBACK_WSI_CREATE,參考3。

b。ssl握手,ws握手,收到101成功后,LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP,

b1。lws_role_transition結束,lws確認ws握手成功,LWS_CALLBACK_CLIENT_ESTABLISHED。

c。如果b。失敗,LWS_CALLBACK_CLIENT_CONNECTION_ERROR,參考3。跳到e。

d。ws斷開,LWS_CALLBACK_CLIENT_CLOSED。

e。LWS_CALLBACK_WSI_DESTROY。

在LWS_CALLBACK_CLIENT_CLOSED清理user。只在LWS_CALLBACK_CLIENT_ESTABLISHED時,才使用user的內存構建內容。

5。四種私有對象:

a。lws_protocol.user,由用戶管理資源,生命周期不短於lws_context。

b。callback的user參數,由eventloop管理資源,生命周期不長於lws。

c。lws_vhost的priv。資源應在eventloop里進行管理,生命周期不長於protocol。

d。lws_vhost的user,由用戶管理資源,生命周期不短於lws_context。

==========

libevent-2.2使用注意

1。bufferevent_openssl_socket_new with BEV_OPT_CLOSE_ON_FREE,不論成功與否,ssl都被接管,不能手動SSL_free。

2。evhttp_connection_base_bufferevent_new,只有成功了bev才會被接管,如果失敗了還得手動進行bufferevent_free。               

3。evhttp_make_request函數后evhttp_request_free會被接管,你就不要再去訪問evhttp_request了,除了eventloop里面的callback。但是失敗是好像有一種例外的情況,39行只TAILQ_REMOVE並沒有evhttp_request_free_auto,對比12行返回-1前evhttp_request_free_auto。而evhttp_connection_fail_只對requests鏈首進行evhttp_request_free_(TAILQ_REMOVE+evhttp_request_free_auto),如果當前req不是鏈首,就只TAILQ_REMOVE,誰管?如果當前req是鏈首,已經被evhttp_connection_fail_處理掉了,還怎么能訪問並TAILQ_REMOVE?

 1 evhttp_make_request(struct evhttp_connection *evcon,
 2     struct evhttp_request *req,
 3     enum evhttp_cmd_type type, const char *uri)
 4 {
 5     /* We are making a request */
 6     req->kind = EVHTTP_REQUEST;
 7     req->type = type;
 8     if (req->uri != NULL)
 9         mm_free(req->uri);
10     if ((req->uri = mm_strdup(uri)) == NULL) {
11         event_warn("%s: strdup", __func__);
12         evhttp_request_free_auto(req);
13         return (-1);
14     }
15 
16     /* Set the protocol version if it is not supplied */
17     if (!req->major && !req->minor) {
18         req->major = 1;
19         req->minor = 1;
20     }
21 
22     EVUTIL_ASSERT(req->evcon == NULL);
23     req->evcon = evcon;
24     EVUTIL_ASSERT(!(req->flags & EVHTTP_REQ_OWN_CONNECTION));
25 
26     TAILQ_INSERT_TAIL(&evcon->requests, req, next);
27 
28     /* We do not want to conflict with retry_ev */
29     if (evcon->retry_cnt)
30         return (0);
31 
32     /* If the connection object is not connected; make it so */
33     if (!evhttp_connected(evcon)) {
34         int res = evhttp_connection_connect_(evcon);
35         /* evhttp_connection_fail_(), which is called through
36          * evhttp_connection_connect_(), assumes that req lies in
37          * evcon->requests.  Thus, enqueue the request in advance and
38          * remove it in the error case. */
39         if (res != 0)
40             TAILQ_REMOVE(&evcon->requests, req, next);
41 
42         return (res);
43     }
44 
45     /*
46      * If it's connected already and we are the first in the queue,
47      * then we can dispatch this request immediately.  Otherwise, it
48      * will be dispatched once the pending requests are completed.
49      */
50     if (TAILQ_FIRST(&evcon->requests) == req)
51         evhttp_request_dispatch(evcon);
52 
53     return (0);
54 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM