ほんとのこと知りたいだけなのに。

夏休みはもうおわり。

SBCL のマニュアル 14 Networking を俯瞰してみる。

upanishad の master - slave の部分のテストが透らず困っている。

仕方なく socket を勉強することに。

とりあえず SBCLのマニュアルを眺めて見ることにした。
英語は Google先生を元に文章が短かくなるように適当に編集した。

それでは開始。

14 Networking

sb-bsd-sockets モジュールは、SBCLのためのBSDソケットAPIを提供します。

CのBSDソケットAPIとPerlのGraham BarrのIO::Socketクラスを参考にしています。

ソケットはCLOSEオブジェクトとして表現されています。

APIの命名規則はBSD名とLispスタイルのバランスを取っています。

14.1 Sockets Overview

ほとんどの関数はBSDソケットAPIでモデル化されています。

BSDソケットは、さまざまなシステムで移植可能(少なくともUNIX標準では "移植可能")で広くサポートされており、文書化されています。

Common Lispのより有用な機能のいくつかを簡単に利用したアプローチにはいくつかの違いがあります:

  • 通常、C APIが-1を返してerrnoを設定する場合、sb-bsd-socketsはエラーを通知します。 すべてのエラーはsb-bsd-sockets:socket-conditionのサブクラスであり、一般的にはerrno値の可能性のあるエラーに対応します。
  • C APIが参照渡しの値を使用する多くの場所で、複数の戻り値を使用します。
  • 引数の長さをすでに知っているので、関数に明示的な長さ引数を渡すことをしばしば避けることができます。
  • IPアドレスとポートは、「network-endian integers」よりも少し優しい方法で表現されます。

14.2 General Sockets

type symbol args
Class socket [sb-bsd-sockets]
Generic Function socket-bind [sb-bsd-sockets] socket &rest address
Generic Function socket-accept [sb-bsd-sockets] socket
Generic Function socket-connect [sb-bsd-sockets] socket &rest address
Generic Function socket-peername [sb-bsd-sockets] socket
Generic Function socket-name [sb-bsd-sockets] socket
Generic Function socket-receive [sb-bsd-sockets] socket buffer length &key oob peek waitall dontwait element-type
Generic Function socket-send [sb-bsd-sockets] socket buffer length &key address external-format oob eor dontroute dontwait nosignal confirm more
Generic Function socket-listen [sb-bsd-sockets] socket backlog
Generic Function socket-open-p [sb-bsd-sockets] socket
Generic Function socket-close [sb-bsd-sockets] socket &key abort
Generic Function socket-shutdown [sb-bsd-sockets] socket &key direction
Generic Function socket-make-stream [sb-bsd-sockets] socket &key input output element-type external-format buffering timeout auto-close serve-events
Method socket-make-stream [sb-bsd-sockets] (socket socket) &key input output (element-type (quote character)) (buffering full) (external-format default) timeout auto-close serve-events
Function socket-error [sb-bsd-sockets] where &optional errno
Generic Function non-blocking-mode [sb-bsd-sockets] socket

14.3 Socket Options

ソケットオプションのサブセットは、一般的なフレームワークを使用してサポートされています。
これにより、必要に応じて簡単に追加することができます。
詳細については、SYS:CONTRIB;SB-BSD-SOCKETS:SOCKOPT.LISPを参照してください。

Cからの名前マッピングはかなり簡単です。
SO_RCVLOWATsockopt-receive-low-water(setf sockopt-receive-low-water) になります。

type symbol args
Function sockopt-reuse-address [sb-bsd-sockets] socket
Function sockopt-keep-alive [sb-bsd-sockets] socket
Function sockopt-oob-inline [sb-bsd-sockets] socket
Function sockopt-bsd-compatible [sb-bsd-sockets] socket
Function sockopt-pass-credentials [sb-bsd-sockets] socket
Function sockopt-debug [sb-bsd-sockets] socket
Function sockopt-dont-route [sb-bsd-sockets] socket
Function sockopt-broadcast [sb-bsd-sockets] socket
Function sockopt-tcp-nodelay [sb-bsd-sockets] socket

14.4 INET Domain Sockets

あなたが知っている、愛しているTCPソケットとUDPソケット。 いくつかの表現の問題:

  • IPv4インターネットアドレスは(符号なしバイト8)のベクトルで表されます。 #(127 0 0 1)
    ポートは6010(整数)だけです。
    このパッケージのユーザーからは、ネットワーク注文データとホスト注文データの間の変換は必要ありません。
  • IPv6インターネットアドレスは、16(符号なしバイト8)のベクトルで表されます。 #(0 0 0 0 0 0 0 0 0 0 0 0 0 0 1)
    ポートは単なる整数です。
    IPv4アドレスに関しては、このパッケージのユーザからネットワーク注文データとホスト注文データの間の変換は必要ありません。
  • ソケットアドレスはaddressとportの2つの値で表されます。
    例えば、(socket-connect socket#(192 168 1 1)80)for IPv4と (socket-connect socket#(0 0 0 0 0 0 0 0) 0 0 0 0 0 0 0 1)80)IPv6のために。
type symbol args
Class inet-socket [sb-bsd-sockets]
Class inet6-socket [sb-bsd-sockets]
Function make-inet-address [sb-bsd-sockets] dotted-quads
Function make-inet6-address [sb-bsd-sockets] colon-separated-integers
Function get-protocol-by-name [sb-bsd-sockets] name

14.5 Local (Unix) Domain Sockets

ローカルドメイン(AF_LOCAL)ソケットはUnixドメインソケットとも呼ばれますが、おそらく他のシステムでも利用可能であるという基準でPOSIXによって名前が変更されました。

ローカルソケットアドレスは文字列であり、ローカルファイルシステムにノードを作成するために使用されます。
これはもちろん、ネットワーク上で使用することはできません。

type symbol args
Class local-socket [sb-bsd-sockets]

14.6 Name Service

現在、ネームサービスは getaddrinfo(3)gethostinfo(3)、またはgethostbyname(3)gethostbyaddr(3)を呼び出すことで実装されています。
名前解決プロセス(DNSやhostsファイルが参照に使用されているかどうかなど)の正確な詳細は、プラットフォームによって異なります。

type symbol args
Class host-ent [sb-bsd-sockets]
Function get-host-by-name [sb-bsd-sockets] node
Function get-host-by-address [sb-bsd-sockets] address
Generic Function host-ent-address [sb-bsd-sockets] host-ent

おわり

なんかなんとなく全体は見えたような気がする。

C のソケットの使い方を理解すれば良さそう.

パッケージは sb-bsd-sockets みたいなので次回はそれを俯瞰してみるか。

babel2 の コンディション

babel2(babel) の condition を眺めてみます。

GitHub - yanqirenshi/babel2: babel をイジって遊ぶためのプロジェクトです。

github.com

コンディションの構成

コンディションの構成(階層)はこんな感じ。

大きくわけて encoding と decoding の二種類あるみたいですね。

                                             +-------+
                                             | error |
                                             +-------+
                                                 |
                                      +------------------------+
                                      | character-coding-error |
                                      +------------------------+
                                                 |
                               +-----------------o------------+
                               |                              |
                    +--------------------------+   +--------------------------+
                    | character-decoding-error |   | character-encoding-error |
                    +--------------------------+   +--------------------------+
                               |
               +---------------o-------------+
               |               |             |
 +---------------------------+ | +------------------------+
 | end-of-input-in-character | | | character-out-of-range |
 +---------------------------+ | +------------------------+
                               |
           +-------------------o----------------------+
           |                                          |             encodings.lisp
 - - - - - | - - - - - - - - - - - - - - - - - - --:--|- - - - - - - - - - - - - - -
           |                  enc-unicode.lisp     :  |               enc-gbk.lisp
           |   +---------------------------+       :  |   +------------------+
           +---| invalid-utf8-starter-byte |       :  +---| invalid-gbk-byte |
           |   +---------------------------+       :  |   +------------------+
           |   +--------------------------------+  :  |   +-----------------------+
           +---| invalid-utf8-continuation-byte |  :  `---| invalid-gbk-character |
           |   +--------------------------------+  :      +-----------------------+
           |   +------------------------+          :
           `---| overlong-utf8-sequence |          :
               +------------------------+          :
symbol parent file
invalid-gbk-byte character-decoding-error enc-gbk.lisp
invalid-gbk-character character-encoding-error enc-gbk.lisp
invalid-utf8-starter-byte character-decoding-error enc-unicode.lisp
invalid-utf8-continuation-byte character-decoding-error enc-unicode.lisp
overlong-utf8-sequence character-decoding-error enc-unicode.lisp
character-coding-error error encodings.lisp
character-encoding-error character-coding-error encodings.lisp
character-decoding-error character-coding-error encodings.lisp
end-of-input-in-character character-decoding-error encodings.lisp
character-out-of-range character-decoding-error encodings.lisp

上の構成図には含めていませんが streams.lisp にもコンディションがあります。
ただ、このコンディションは streams.lisp で閉じられているので上の構成図には入れていません。
(export もされていません)

symbol parent file
in-memory-stream-error stream-error streams.lisp
in-memory-stream-closed-error in-memory-stream-error streams.lisp
wrong-element-type-stream-error stream-error streams.lisp

コンディションを発火させるオペレータ

コンディションを発火させるオペレータハ以下の二つです。

  • encoding-error
  • decoding-error

おわり

朧げですが全体像が掴めました。

これの結果で babel2.conditions を新設してそこにコンディションを分離しました。

また少しコードの見通しが良くなりました。

babel2 パッケージごとの依存関係

パッケージ定義

パッケージの定義はこんな感じ。

綺麗なものである。

 +--------+                                           +-------------+
 | babel2 |<-----------------------------------------o| common-lisp |
 |        |                            +------------+ |             |
 |        |<--------------------------o| alexandria | |             |
 |        |    +------------------+    |            | |             |
 |        |<--o| babel2-encodings |<--o|            | |             |
 |        |    |                  |    +------------+ |             |
 |        |    |                  |<-----------------o|             |
 +--------+    +------------------+                   +-------------+

ソース

babel2

まぁこちらのパッケージはbabel2-encodingsに依存することは問題ない。

だけど、いちおう調べておく。

わかる範囲で。

結果はこんな感じ。

file babel2-encodings 依存
external-format.lisp lookup-mapping が依存
sharp-backslash.lisp sharp-backslash-reader が依存
strings.lisp なし。ほんまかな。

babel2-encodings

こちらのパッケージでbabel2を参照しているものがいると問題。

結果としては一つあった。

file babel2 依存
enc-ascii.lisp なし。
enc-cp1251.lisp なし。
enc-cp1252.lisp なし。
enc-ebcdic-int.lisp なし。
enc-ebcdic.lisp なし。
enc-gbk.lisp なし。
enc-iso-8859.lisp なし。
enc-jpn.lisp なし。
enc-koi8.lisp なし。
enc-unicode.lisp なし。
encodings.lisp なし。
gbk-map.lisp gbk-unicode-mapping が依存
jpn-table.lisp なし。

パッケージの依存関係で衝突が発生している。

以下の場所で衝突が発生していることがわかった。

結論としては babel2:unicode-string を外出しに出来れば寄さそう。

item value
file gbk-map.lisp
symbol gbk-unicode-mapping
confrict babel2:unicode-string をコールしている。

babel2:unicode-string とは?

unicode-string は type な様子。

file:strings.lisp で定義されています。

対応としては type は別パッケージにして、各パッケージがそれを :use する。で解決できそう。

deftype は別パッケージにする。

以下のイシューで別パッケージにする対応を実施しました。

[deftype を外出しにする。 #6]9https://github.com/yanqirenshi/babel2/issues/6)

これでパッケージの依存度合いは以下のように綺麗になりました。

 +--------+                                                +-------------+
 | babel2 |<----------------------------------------------o| common-lisp |
 |        |                            +------------+      |             |
 |        |<--------------------------o| alexandria |      |             |
 |        |    +------------------+    |            |      |             |
 |        |<--o| babel2.encodings |<--o|            |      |             |
 |        |    |                  |    +------------+      |             |
 |        |    |                  |<----------------------o|             |
 |        |    |                  |    +--------------+    |             |
 |        |    |                  |<--o| bable2.types |<--o|             |
 |        |    +------------------+    |              |    |             |
 |        |<--------------------------o|              |    |             |
 +--------+                            +--------------+    +-------------+

おわり。

やはり型はパッケージの共通領域で定義したほうが良いよね。

Class どか Constant とかもその方が良いんじゃないかな。