調べなきゃ寝れない！と調べたら余計に寝れなくなったソケットの話


#課題

最近良く名前を聞くようになったソケット通信が速度が早くて良い的な話をしてたものの、ソケットってそんなに最近出てきたようなことだっけか？と曖昧になったので調べなきゃ寝れない！ということで調べてみた

#プロトコルの種類

通信といえばTCP/UDPだろうと再度確認

|プロトコル|概要|備考|
|----|-------------------|----------------|
|TCP/IP|信頼性が高い|データグラム(電文)が届いたかどうかを誤りチェックしていて、届いていない場合は再送要求をする。<br>到着順序が保証されていて、到着したデータは並べ替えられる。<br>それらが失敗した場合はエラーになるようになっている|
|UDP/IP|基本的な通信|データグラム(電文)は一方的に送信され、相手に届いたかどうかのチェック等はしない。<br>エラーの検知はしない。変な受信データもただ破棄されるのみのため、その分単純で高速。|

ただ、ソケットの話はここでは出てこない

#ソケットはどこの話か？

ソケットのタイプ
![osi.png](https://qiita-image-store.s3.amazonaws.com/0/8726/f0a56f73-b1f5-95bb-8dba-59d889e76e62.png "osi.png")

OSI参照モデルではセッション層部分。TCP/UDPより上のレイヤーだった。

#あれ？ソケットって普通の通信じゃね？

ソケットにも種類があるのか調べてみた。

|ソケット|概要|特定方法|通信箇所|
|---|---|---|---|
|INETドメイン|ネットワーク上でマシンを越えてのプロセス間通信|IPアドレス+ポート番号|他マシンと通信可|
|UNIXドメイン|同じマシン上で動いているプロセスが通信を行うためのソケット。<br>アドレス・名前空間としてファイルシステムを使用している。<br>ファイルシステム内のinodeとしてプロセスから参照される。|ファイル名で一致|自マシンのみ|

なるほど、最近ソケット通信、ソケット通信と言ってるのはUNIXドメインソケットの事か！

#UNIXドメインソケットって何がいいの？

[Performance Analysis of Various Mechanisms for Inter-process Communication](http://osnet.cs.binghamton.edu/publications/TR-20070820.pdf)に素晴らしい検証があった。

> It was hypothesized that pipes would have the highest throughtput due to its limited functionality, since it is half-duplex, but this was not true. For almost all of the data sizes transferred, Unix domain sockets performed better than both TCP sockets and pipes, as can be seen in Figure 1 below.

> On some machines, Unix domain sockets reached transfer rates as high as 1500 MB/s. 

![osnet_cs_binghamton_edu_publications_TR-20070820_pdf-2.png](https://qiita-image-store.s3.amazonaws.com/0/8726/a8ab6c05-5b5a-d951-c89a-5104846c19c8.png "osnet_cs_binghamton_edu_publications_TR-20070820_pdf-2.png")

UNIXドメインソケットは、TCPソケット(INETドメインソケット)よりも遥かにスループットが優れてるらしい。Solaris(UltraSPARC processor)ではアーキテクチャの違いからUNIXドメインソケットのほうが遅いらしい。

よし、これで寝れる

[Redis コア開発者 @pnoordhuis のツイート](https://twitter.com/pnoordhuis/status/195614999283109888)

> TIL that "an abstract socket address is distinguished by the fact that sun_path[0] is a null byte ('\0')". Anybody knows why this exists?

えーと、抽象名前空間ソケット？？まだ、UNIXドメインソケットにも種類があるのか？

#UNIXドメインソケットの種類

[unix - sockets for local interprocess communication](http://man7.org/linux/man-pages/man7/unix.7.html)

|種類|概要|
|---|---|
|ファイルシステムパス名(pathname)|きっと一番知られている一般的な手法。[bind(2)](http://linuxjm.sourceforge.jp/html/LDP_man-pages/man2/bind.2.html)を使用して、NULL終端(\0)されたファイルシステム上のパスに結びつけることができる。ファイルを使用しているため、パーミッションを調整する必要がある。サーバプロセスが終了するときには、[unlink(2)](http://linuxjm.sourceforge.jp/html/LDP_man-pages/man2/unlink.2.html)で名前を削除し、場合によってはそれが参照しているファイルも削除するのがお作法。
|無名(unnamed)|[bind(2)](http://linuxjm.sourceforge.jp/html/LDP_man-pages/man2/bind.2.html)を使ってパス名に結び付けることができないストリーム型のソケットは名前を持たない。[socketpair(2)](http://linuxjm.sourceforge.jp/html/LDP_man-pages/man2/socketpair.2.html)を使うと、名前のついていない CONNECTED なソケットのペアが生成される。fork してファイルディスクリプターを繋ぎ直してあげれば、pipe で実現するのと同じような双方向のプロセス間通信ができる。|
|抽象名前空間(abstract)|sun_pathにファイルシステムのパスではなく、NULLバイト(\0)であることで区別される。NULLバイト以降に名前(文字列)を渡すが、ファイルパス名とは関係ない。ファイルシステムと紐付いていないので、 ファイルシステムのパーミッションなどに関係なくソケット通信できてしまう。Linuxでのみ利用可能。[unlink(2)](http://linuxjm.sourceforge.jp/html/LDP_man-pages/man2/unlink.2.html)で終了する必要がない。|

#どのUNIXドメインかを見極めるには

`$netstat -al --protocol=unix` で確認する

###ファイルシステムパス名

I-Node path部分にファイルパス名が表示されている

```
Active UNIX domain sockets (only servers)
Proto RefCnt Flags       Type       State         I-Node Path
unix  2      [ ACC ]     STREAM     LISTENING     154823 /var/lib/mysql/mysql.sock
```

###無名

I-Nodeは割り振られるが、pathは表示されない

```
Active UNIX domain sockets (only servers)
Proto RefCnt Flags       Type       State         I-Node Path
unix  3      [ ]         STREAM     CONNECTED     175322
```

###抽象名前空間

I-Node path部分に@がついた名前が表示される

```
Active UNIX domain sockets (only servers)
Proto RefCnt Flags       Type       State         I-Node Path
unix  2      [ ACC ]     STREAM     LISTENING     6653   @/com/ubuntu/upstart
```

#UNIXドメインソケットをサポートしているサービス

|ミドルウェア|概要|種類|使用方法|連携ミドルウェア|
|---|---|---|---|---|
|Nginx|web server|pathname|[server divective](http://wiki.nginx.org/HttpUpstreamModule)|unicorn, gunicorn, php-fpm, etc... |
|Unicorn|ap server|pathname|[Public Instance Methods](http://unicorn.bogomips.org/Unicorn/Configurator.html)
|Mysql|db server|pathname||||
|Redis|KVS|pathname|[How fast is Redis?](http://redis.io/topics/benchmarks)|||
|Memcached|KVS|pathname|[Using memcached](http://docs.oracle.com/cd/E17952_01/refman-5.6-en/ha-memcached-using.html)
|upstart|deamon|abstract|||
|sytemd|deamon|abstract|||
|OS?|kernelプロセス?|unnamed|||

#まとめ

ソケット通信は今度からUNIXドメインソケット通信と言うこと(どのマニュアルにもちゃんと書いてあったけど笑)。TCPで接続することばっかりやってきたので、気にもしてなかったがKVSとかの接続はUNIXドメインソケット通信にしたらもう少し効率よく使えるのではないかと。まだまだ、調べたらいろいろありそうなので継続調査。

もう寝ます笑