Libevent公式ドキュメント学習ノート(2.buffereventセクション)


本住所:https://segmentfault.com/a/1190000005601925
Libeventの補助関数とデータ型
ヘッダファイルはです.以下には、自分が使う部分だけをリストします.
基本タイプevutil_socket_tSocketの抽象.Windows以外のシステムはintタイプです.Windowsの互換性を考えるなら、このタイプをお勧めします.
ひょうじゅんせいけい
以下に、いくつかのデータ長の定義を示します.
    ----------------------------------------------------------
       Type                                      
    ----------------------------------------------------------
    ev_uint64_t      64      x    EV_UINT64_MAX        0
    ev_int64_t       64      √    EV_INT64_MAX    EV_INT64_MIN
    ev_uint32_t      32      x    EV_UINT32_MAX        0
    ev_int32_t       32      √    EV_INT32_MAX    EV_INT32_MIN
    ev_uint16_t      16      x    EV_UINT16_MAX        0
    ev_int16_t       16      √    EV_INT16_MAX    EV_INT16_MIN
    ev_uint8_t       8       x    EV_UINT8_MAX         0
    ev_int8_t        8       √    EV_INT8_MAX     EV_INT8_MIN

その他のタイプev_ssize_tev_off_tアダプティブ関数のマクロ
#define evutili_timer_add(tvp, uvp, vvp)
#define evutili_timer_sub(tvp, uvp, vvp)

timevalデータの加減を計算するマクロ、vvp=tvp+/-uvp.注意三者ともポインタを使う
#define evutil_timerclear(tvp)
#define evutil_timerisset(tvp)

timevalをクリアしたり、クリアされたかどうかを判断したりします#define evutil_timercmp(tvp, uvp, cmp)判断timevalの前後、その中のcmpは比較的に富豪で、例えば==,<=,>=,<,>,!=,int evutil_gettimeofday (struct timeval *tv, struct timezone *tz);
Socket関連関数
#define evutil_socket_geterror (sock)
#define evutil_socket_error_to_string (errcode)

指定したsocketのerror codeを取得し、読み取り可能なstringに変換
int evutil_make_socket_nonblocking (evutil_sopcket_t sock);

socketをブロックしません.
文字列アクション
ev_int64_t evutil_strtoll (const char *s, char **endptr, int base);
int evutil_snprintf (char *but, size_t buflen, const char *format, ...);
int evutil_vsnprintf (char *bug, size_t buflen, const char *format, va_list ap);

データ構造体
#define evutil_offsetof (type, field)

Bufferevent:概念と基本知識
従来のlibeventの使用方法:
  • データを入れる必要がある場合、buffer
  • にデータを格納する
  • socket書き込み待ち
  • できるだけsocketにもっと多くのdataを書く
  • まだdataが書き込まれていない場合は、socket書き込み可能
  • を待つ
    ヘッダファイルstruct evbufferを使用してbuffereventを使用し、read/write呼び出しを節約し、1つのbufferにデータを入れる/取り出すだけで現在のbuffereventはTCPのみをサポートし、将来的にはUDPをサポートする可能性があります.各buffereventにはread bufferと1つのwrite bufferがあり、いずれもwatermarksです.これは後で話します.
    コールバックとbufferevent
    BuffereventはRead low-water mark(水位線)というものを用いてコールバック関数の呼び出しタイミングを定義する.次のwatermarksはいくつかあります:Read high-water mark:read bufferの量がこれ以上大きい場合、callbackが呼び出されます.デフォルトは0です.つまり、データがあるとコールバックします.Write low-water mark:read bufferの量がこれ以上大きい場合は、buffer内のデータがこの値を下回るまでreadを停止し、readを再開します.デフォルトは無限です.Write high-water mark:write bufferの量がこれ以上小さい場合、コールバックが呼び出されます.デフォルトは0BEV_EVENT_READING:buffereventでこの値は直接使用されません.後述を参照
    Buffereventには、データ以外の時間やエラーを通知するためのエラーコールバックやイベントコールバックもあります.操作中にエラーが発生しました.BEV_EVENT_WRITINGを呼び出して、エラーが発生したかどうかを判断する必要がありますBEV_EVENT_ERROREVUTIL_SOCKET_ERROR()BEV_EVENT_TIMEOUT:要求接続が完了しました
    遅延コールバックは一般的にbuffereventのcallback時にすぐに呼び出されます.ただし、呼び出し関係が複雑であればバグが発生する可能性があります.この場合、buffereventを遅延(BEV_EVENT_EOF)に設定すると、event loopでコールバック関数が実行され、単一スレッドになります.
    BuffereventのオプションBEV_EVENT_CONNECTED:buffereventがリリースされると、下位転送defered:bufferevent用lockBEV_OPT_CLOSE_ON_FREE:callbackを遅延BEV_OPT_THREADSAFE:デフォルトでTHREADSCAFEフラグがある場合、callbackを呼び出すとロックされます.このフラグを使用するのはTHREADSAFEフラグがあってもcallbackを呼び出してもロックしない
    SOcketベースのbuffereventの使用
    struct bufferevent *bufferevent_socket_new (
                            struct event_base *base,
                            evutil_socket_t    fd,
                            enum bufferevent_options options);

    ここでのfdは指定しなくてもよいが,このときfdのパラメータは−1である.fdを指定した場合、このfdは既にnonblockである必要があります.
    int bufferevent_socket_connect (struct bufferevent *bev,
                                    struct sockaddr    *address,
                                    int                 addrlen);

    これはBEV_OPT_DEFER_CALLBACKSのパッケージです.bevのfdが-1の場合、BEV_OPT_UNLOCK_CALLBACKSが自動的に呼び出され、nonblockが設定されます.その後、非同期呼び出しconnect();fdが指定されている場合は、bevにsocket()操作を行うように伝えるだけです.通常、これはconnect()コールバックを引き起こす
    int bufferevent_socket_connect_hostname (
                    struct bufferevent *bev,
                    struct event_base  *dns_base,
                    int                 family,
                    const char         *hostname,
                    int                 port);

    これはconnect()パッケージの別のバージョンですが、ターゲットはhostnameに変更されます.これによりbuffereventはDNSを自動的に解析します.このうちBEV_EVENT_CONNECTEDは、connect(),family,AF_INET,AF_INET6のいずれかの値を選択できます.  dns_baseパラメータはオプションです.NULLの場合、buffereventはDNS解析が完了するまでブロックされます.もちろんお勧めしません.パラメータが付いている場合、libeventはDNSリクエストを非同期で処理します.残りの作業は上のconnectパッケージと同じです.
    int bufferevent_socket_get_dns_error (struct bufferevent *bev);

    汎用bufferevent操作
    void bufferevent_free (struct bufferevent *bev);

    bffereventを解放します.callbackがdeferedの場合、buffereventはcallbackが戻ってから解放されます.BEV_が指定されている場合OPT_CLOSE_ON_FREE、そうするとsocketもcloseに落とされます.
    typedef void (*bufferevent_data_cb) (struct bufferevent *bev, void *ctx);
    typedef void (*bufferevent_event_cb) (struct bufferevent *bev, short events, void *ctx);
    void buffevent_setcb (struct buffevent    *bufev,
                          bufferevent_data_cb  readcb,
                          bufferevent_data_cb  writecb,
                          bufferevent_event_cb eventcb,
                          void                *cbarg);
    void bufferevent_get_cb (struct buffevent     *bufev,
                             bufferevent_data_cb  *readcb_ptr,
                             bufferevent_data_cb  *writecb_ptr,
                             bufferevent_event_cb *eventcb_ptr,
                             void                **cbarg_ptr);

    を選択します.buffereventのcallbackを取得します.あるcallbackを使用したくない場合は、NULLが入力されます.
    void bufferevent_enable (struct bufferevent *bufev, short events);
    void bufferevent_disable (struct bufferevent *bufev, short events);
    short bufferevent_getenabled (struct bufferevent *bufev);

    指定したcallbackを有効/無効にします.デフォルトでは、初期化されたbufferevent、writeは使用できますが、readは禁止されています.
    void bufferevent_setwatermark (struct buffevent *bev,
                                   short             events,
                                   size_t            lowmark,
                                   size_t            highmark);

    watermarkを設定します.high-watermarkの場合、0は無限を表す.
    struct evbuffer *bufferevent_get_input (struct bufferevent *bev);
    struct evbuffer *bufferevent_get_output(struct bufferevent *bev);

    buffereventで対応するread/write bufferを取得します.
    int bufferevent_write (struct bufferevent *ev, const void *data, size_t size);
    int bufferevent_write_buffer (struct bufferevent *bev, struct evbuffer *buf);

    関数1:buffereventに直接データを追加する関数2:evbufferのすべての内容をbuffereventに追加し、evbufferを晴れ渡る
    size_t bufferevent_read (struct bufferevent *bev, void *data, size_t size);
    int bufferevent_read_buffer (struct bufferevent *bev, struct evbuffer *buf);

    関数1:buffereventから直接データを読み出し、データ長を返す関数2:buffereventのすべてのデータをevbufferに抽出する
    void bufferevent_set_timeouts (struct bufferevent  *bev,
                                   const struct timeval *timeout_read,
                                   const struct timeval *timeout_write);

    timeoutを設定して、しばらくデータがない場合にコールバック関数をトリガーします.この場合の実践にはAF_UNSPECビットが含まれます
    int bufferevent_flush (struct bufferevent *bufev,
                           short               iotype,
                           enum bufferevent_flush_mode state);

    可能な限り多くのデータの読み取り/書き込みを強制します.この関数は現在socketには役に立たない.
    タイプ固有のbufferevent関数
    以下の関数の意味は文字通り、特に説明しません.
    int bufferevent_priority_set (struct bufferevent *bev, int pri);
    int bufferevent_get_priority (struct bufferevent *bev);
    
    int bufferevent_setfd (struct bufferevent *bev, evutil_socket_t fd);
    evutil_socket_t bufferevent_getfd (struct bufferevent *bev);
    
    struct event_base *bufferevent_get_base (struct bufferevent *bev);
    struct bufferevent *bufferevent_get_underlying (struct bufferevent *bev);
    
    void bufferevent_lock   (struct bufferevent *bev);
    void buyfferevent_unlock(struct bufferevent *bev);

    Bufferevents:詳細トピック
    ここではbuffereventの高度な機能についてたくさん話しました.この記事は、使用する部分のみをリストします.
    read/writeごとの長さを制限
    int bufferevent_set_max_single_read (struct bufferevent *bev, size_t size);
    int bufferevent_set_max_single_write(struct bufferevent *bev, size_t size);

    対応するget関数もあります
    そくどせいげん
    #define EV_RATE_LIMIT_MAX    EV_SSIZE_MAX
    struct ev_token_bucket_cfg;
    struct ev_token_bucket_cfg *ev_token_bucket_cfg_new (
                                    size_t read_rate,     size_t read_burst,
                                    size_t write_rate,    size_t write_burst,
                                    const struct timeval *tick_len);
    void ev_token_bucket_cfg_free (struct ev_token_bucket_cfg *cfg);
    int bufferevent_set_rate_limit (struct bufferevent         *bev,
                                    struct ev_token_bucket_cfg *cfg);

    ここで、BEV_EVENT_TIMEOUTの最初の4つの関数の単位はいずれもev_token_bucket_cfg_new()であり、bytes/tickの単位はtickで指定される.tick_lenがNULLの場合、デフォルトは1秒です.
    BuffereventsとSSL
    ここではbuffereventでSSLをどのように使うかという重要な内容です.LibeventはSSLの深さを結合し、buffereventを使用してSSL通信を容易に行うことができます.ええと、欠点はlibeventとOpenSSLの欠点の集合です.実は組み込み開発にとって、CPUは分立しているので、性能上の欠点は明らかではありません.最大の問題はディスクスペースを占有することです.Libeventのライブラリ自体は小さくなく、OpenSSLを加えるともっと大きいです.私がlibeventを理解したとき、私たちのシステムはすでに他の非同期I/OとSSLライブラリを変更する準備ができていたので、私も別のツッコミを見ませんでした.私たちは何年もlibeventとOpenSSLを完全に置き換える時間がありませんでした.その間、私自身はlibev、libuv、PolarSSL(mbedTLS)、cyaSSLを見ました.
    シリーズ
    Libevent公式文書学習ノート(1.libevent_core部分)Libevent公式文書学習ノート(2.bufferevent部分)(本稿)Libevent公式文書学習ノート(3.evbuffer部分)