NNG (NanoMsg NewGeneration)メモ
NNGとは
公式サイト
公式レポジトリ特徴
-
zeromq
同様ブローカーレス - 先行する
nanomg
に対してスケーラビリティを追求したもの -
zeromq
やnanomg
とは異なり、プロトコルごとに関数セットを分割している- 新しいプロトコルは、新しい関数セットを追加するだけ
- APIの複雑さとのトレードオフ
コンテキスト
- 1つのソケットを複数のスコープに分け、並行的に通信する考え
-
zeromq
のコンテキストとは考え方が違うことに注意 -
raw
モードではサポートされない
-
- 一つの
REP
ソケットで複数のREQ
を受信に使われる- リクエストは非同期IOで受ける
-
zeromq
ではポーリングで実現してたやつ
通常
- サーバ側の受信は1リクエスト複数コンテキスト
- クライアント側は1リクエスト1コンテキスト
が無難
トランスポートレイヤー
nng
のトランスポートはURL
を用いてzeromq
に類似した記述を行う。
-
inproc (inproc://<IDENTIFIRE>)
- 同一プロセス内での通信
- スレッド間をシェアードナッシングに保つのに役立つ
- ゼロコピー
- 別アプリケーションで同じURLを使用しても干渉しない
-
ipc (ipc://<PATH>)
- 同一ホスト内の別プロセス間通信
- UNIXプラットホームではPOSIXドメインソケットを使用
- Windows環境では
PATH
としてUNC
や名前付きパイプ
を使用する
-
BSDソケット (socket://...)
- 実体は
TCPソケット
- 実体は
-
TCP (tcp://<IP Address:PORT> or tcp://HOSTNAME:PORT)
- TCP/IPネットワーク間で通信
- IPv4とIPv6をサポート
- IPv6の場合は
tcp://[::1]:80
のようにブラケットで囲む - リスナーURLは、
tcp://0.0.0.0:80
やtcp://*:80
な感じ
- IPv6の場合は
-
TLS (tls+tcp://<IP Address:PORT> or tls+tcp://HOSTNAME:PORT)
- TLS v1.2による通信
- ネットワークトランスポートは
TCP
- ネットワークトランスポートは
- mbedTLS依存
-
URL
の記述はTCP
に準拠する - 公式レポジトリに、
optionally v1.3
って書かれてるから、そっちもいけるのかも- ドキュメントには書かれてない
- TLS v1.2による通信
-
WebSocket (ws://<IP Address:PORT> or ws://HOSTNAME:PORT)
-
URL
の記述はTCP
に準拠する -
URL
としてwss://
も使用可能
-
-
ZeroTier (zt://<DIGEST>)
- ZeroTier間で通信
-
Stream
- 任意のプロトコルに対するプロキシ的立ち位置
- listener:
nng_stream_listener_alloc
関数でソケットを作成-
url
指定ならnng_stream_listener_alloc_url
関数を使う
-
- dealer:
nng_stream_dialer_alloc
関数でソケットを作成-
url
指定ならnng_stream_dialer_alloc_url
関数を使う
-
ipcのオプション
なし
inprocのオプション
-
NNG_OPT_IPC_PERMISSIONS
-
NNG_OPT_IPC_SECURITY_DESCRIPTOR
-
NNG_OPT_LOCADDR
-
NNG_OPT_REMADDR
-
NNG_OPT_PEER_GID
-
NNG_OPT_PEER_PID
-
NNG_OPT_PEER_UID
-
NNG_OPT_PEER_ZONEID
-
NNG_OPT_URL
ソケットのオプション
BSDソケット
-
NNG_OPT_PEER_GID
-
NNG_OPT_PEER_PID
-
NNG_OPT_PEER_UID
-
NNG_OPT_PEER_ZONEID
TCP
-
NNG_OPT_LOCADDR
-
NNG_OPT_REMADDR
-
NNG_OPT_TCP_KEEPALIVE
-
NNG_OPT_TCP_NODELAY
NNG_OPT_URL
TLSのオプション
-
NNG_OPT_LOCADDR
-
NNG_OPT_REMADDR
-
NNG_OPT_TCP_KEEPALIVE
-
NNG_OPT_TCP_NODELAY
-
NNG_OPT_TLS_AUTH_MODE
-
NNG_OPT_TLS_CA_FILE
-
NNG_OPT_TLS_CERT_KEY_FILE
-
NNG_OPT_TLS_CONFIG
-
NNG_OPT_TLS_VERIFIED_
-
NNG_OPT_TLS_PEER_CN
-
NNG_OPT_TLS_PEER_ALT_NAMES
-
NNG_OPT_URL
WebSocketのオプション
-
NNG_OPT_WS_REQUEST_HEADERS
- (string) Concatenation of multiple lines terminated by CRLF sequences, that can be used to add further headers to the HTTP request sent when connecting. This option can be set on dialers, and retrieved from pipes.
-
NNG_OPT_WS_RESPONSE_HEADERS
- (string) Concatenation of multiple lines terminated by CRLF sequences, that can be used to add further headers to the HTTP response sent when connecting. This option can be set on listeners, and retrieved from pipes.
-
NNG_OPT_WS_RECV_TEXT
- (bool) Enable receiving of TEXT frames at the WebSocket layer. This option should only be used with the low level nng_stream API. When set, the stream will accept in-bound TEXT frames as well as BINARY frames.
- The SP protocols (such as REQ) require BINARY frames as they pass binary protocol data. Hence this option should not be used with such protocols.
- RFC 6455 requires that TEXT frames be discarded and the connection closed if the frame does not contain valid UTF-8 data. NNG does not perform any such validation. Applications that need to be strictly conformant should check for this themselves.
-
NNG_OPT_WS_SEND_TEXT
- (bool) Enable sending of TEXT frames at the WebSocket layer. This option should only be used with the low level nng_stream API. When set, the stream will send TEXT frames instead of BINARY frames.
- NNG does not check the frame data, and will attempt to send whatever the client requests. Peers that are compliant with RFC 6455 will discard TEXT frames (and break the connection) if they do not contain valid UTF-8.
-
NNG_OPT_TLS_CONFIG
- (nng_tls_config *) The underlying TLS configuration object for wss:// endpoints. A hold is placed on the underlying configuration object before returning it. The caller should release the object with nng_tls_config_free() when it no longer needs the TLS configuration.
- Use this option when advanced TLS configuration is required.
-
NNG_OPT_TLS_CA_FILE
- (string) Write-only option naming a file containing certificates to use for peer validation. See nng_tls_config_ca_file() for more information.
-
NNG_OPT_TLS_CERT_KEY_FILE
- (string) Write-only option naming a file containing the local certificate and associated private key. The private key used must be unencrypted. See nng_tls_config_own_cert() for more information.
-
NNG_OPT_TLS_AUTH_MODE
- (int) Write-only option used to configure the authentication mode used. See nng_tls_config_auth_mode() for more details.
-
NNG_OPT_TLS_VERIFIED
- (bool) Whether the remote peer has been properly verified using TLS authentication. May return incorrect results if peer authentication is disabled.
-
NNG_OPT_TLS_PEER_CN
- (string) This read-only option returns the common name of the peer certificate. May return incorrect results if peer authentication is disabled.
-
NNG_OPT_TLS_PEER_ALT_NAMES
- (string list) returns string list with the subject alternative names of the peer certificate. May return incorrect results if peer authentication is disabled.
プロトコル
- REQ/REP
- req -> rep -> reqの一方向通信
- req:
nng_req0_open
関数でソケットを作成する - rep:
nng_rep0_open
関数でソケットを作成する - コンテキストサポート
- PUB/SUB
- pub -> subの一方向通信
- pub:
nng_pub0_open
関数でソケットを作成する - sub:
nng_sub0_open
関数でソケットを作成する
- PUSH/PULL
- push -> pullの一方向通信
- push:
nng_push0_open
関数でソケットを作成する - pull:
nng_pull0_open
関数でソケットを作成する
- PAIR
- p2pの双方向通信
-
nng_pair0_open
関数でソケットを作成する
- SURVAYOR/RESPONDENT
- survayor -> respondantの一方向通信
- SURVAYOR: ブロードキャスト
-
nng_surveyor0_open
関数でソケットを作成する - コンテキストサポート
- 複数のリクエストを一斉配信
- 最新の返信を採用
-
- RESPONDENT: Finish or Discardを任意に選択可能
- 時間切れでDiscard
-
nng_respondent0_open
関数でソケットを作成する
- BUS
- ネットワークメッシュ間のメッセージ交換
- P2P
-
nng_bus0_open
関数でソケットを作成する -
cooked
モードはヘッダレス -
row
モードはpipe id
が渡される
非同期IO
- ノンブロッキング
- 結果は登録したコールバックで受ける
-
nng_aio_alloc
関数でコールバックを登録する - 第3引数(
void *
)に渡した値がコールバックに渡される- ソケットなどを渡す
-
- リクエストキャンセルをサポートする
- タイムアウトによるキャンセルもサポート
IOの待機
複数のソケットの待機を
while (true) {
nng_aio_wait(...); // 一つ目のソケットの待機
nng_aio_wait(...); // 二つ目のソケットの待機
}
とすると、一つ目のソケットの処理が完了するまで、二つ目のソケットの処理が行えなくなり、スループットが低下する。
回避策として、それぞれのソケット用に別スレッドを起動して、そこで待機させる。
無限ループのままだとスレッドを終わらせることができないため、キャンセルやソケットクローズかどうかの判定も行う。
while (true) {
nng_aio_wait(...);
switch (nng_ctx_result(...) {
NNG_ECANCELED => {
// キャンセルされた場合
break;
},
NNG_ECLOSED => {
// ソケットがクローズされた場合
break;
},
else => {
// 正常系
// 受け取ったメッセージをハンドリングする
}
}
}
受信の多重化について
- 後方互換性のため
nng_poll
が残されてはいるが、非同期IO+コンテキストで組むことが基本。 - 非同期IO+コンテキストの場合、単に複数のソケットを受信待ちにしておけばよく、やってきたものから順に処理してくれる。
- ただし場合によってはREQ->REQになる可能性もあるため、自前での状態遷移の管理とキューイングが重要
HELOメッセージ
サーバがnng_listen
でバインド後、nng_ctx_recv
を呼ぶことでやっと受信待ちにできる
- しかしクライアントは
nng_listen
でバインドが完了していれば、nng_connect
は成功する -
nng_ctx_recv
未完了で投げられたメッセージは捨てられる
クライアントはnng_connect
を呼んだ後
- サーバに
HELO
メッセージを送る - サーバは
ACK
をレスポンスとして返す
のフローの成立をもって接続の確立とみなす必要がある。
nng_ctx_recv
前にHELO
を送ってしまうケースの対策として、REQソケットの送信にタイムアウトを設ける。
REQ
ソケットはタイムアウト後に自動再送するため、サーバが生きていれば、いずれは接続が確立する