ソケットプログラミング HOWTO
****************************

Author:
   Gordon McMillan


Abstract
^^^^^^^^

ソケットはそこかしこで使われているが、最大級に誤解されている技術でもあ
る。この文書はソケットの全体像を俯瞰しており、チュートリアルとしてはあ
まり役に立たない。実際に動くモノを完成させるには、他にもやらなければい
けないことがあるからだ。この文書はソケットの微妙なところ (たくさんある
) まではカバーしていないが、恥ずかしくない使い方ができるようになる程度
の情報は得られるはずだ。


ソケット
========

I’m only going to talk about INET sockets, but they account for at
least 99% of the sockets in use. And I’ll only talk about STREAM
sockets - unless you really know what you’re doing (in which case this
HOWTO isn’t for you!), you’ll get better behavior and performance from
a STREAM socket than anything else. I will try to clear up the mystery
of what a socket is, as well as some hints on how to work with
blocking and non-blocking sockets. But I’ll start by talking about
blocking sockets. You’ll need to know how they work before dealing
with non-blocking sockets.

話を理解しにくくしている要因として、「ソケット」という言葉が文脈によっ
て微妙に違うものを指すことが挙げられる。そこでまず、「クライアント」ソ
ケット - 対話の両端 - と「サーバ」ソケット - 電話交換手みたいなもの -
の区別を付けておこう。クライアントアプリケーション (たとえばブラウザ)
は「クライアント」ソケットだけを使うが、話し相手のウェブサーバは「サー
バ」ソケットと「クライアント」ソケットの両方を使う。


歴史
----

各種 IPC (Inter Process Communication (プロセス間通信) の中でも、ソケ
ットは群を抜いて人気がある。どのプラットフォームにも、ソケットより速い
IPC はあるだろう。だが、プラットフォームをまたぐ通信はソケットの独擅場
だ。

ソケットは BSD Unix の一部としてバークレイで発明され、インターネットの
普及と共に野火のごとく広まった。それももっともなことで、ソケットと
INET のコンビによって世界中どんなマシンとも、信じられないほど簡単 (少
なくとも他のスキームと比べて) に通信できるようになったのだ。


ソケットの作成
==============

あなたがリンクをクリックしてこのページに来たとき、ブラウザは大雑把に言
って次のようなことをしたのである:

   #create an INET, STREAMing socket
   s = socket.socket(
       socket.AF_INET, socket.SOCK_STREAM)
   #now connect to the web server on port 80
   # - the normal http port
   s.connect(("www.mcmillan-inc.com", 80))

この "connect" が完了すると、ソケット "s" を使ってこのページ文章への要
求を送ることができるようになる。その同じソケットが返答を読み、そして破
壊される。そう、破壊される。クライアントソケットは通常、一回 (か少数の
) やり取りで使い捨てになるのだ。

ウェブサーバで起こる事柄はもう少し複雑だ。まず「サーバソケット」を作る
:

   #create an INET, STREAMing socket
   serversocket = socket.socket(
       socket.AF_INET, socket.SOCK_STREAM)
   #bind the socket to a public host,
   # and a well-known port
   serversocket.bind((socket.gethostname(), 80))
   #become a server socket
   serversocket.listen(5)

ここで注意すべき点がいくつかある: 今回はソケットが外界に見えるよう、
"socket.gethostname()" を使った。 "s.bind(('localhost', 80))" や
"s.bind(('127.0.0.1', 80))" でも「サーバ」ソケットにはなるが、それだと
同じマシン内にしか見えないものになってしまう。 "s.bind(('', 80))" はこ
のマシンが持っている全てのアドレスで接続可能になるようにという指定にな
る。

ふたつめ: 小さな番号のポートは大抵、「ウェルノウン (有名)」なサービス
(HTTP, SNMP 等々) のために取ってある。お遊びで使うのなら適当に大きな数
(4桁) を使おう。

最後に: "listen" の引数はソケットライブラリに、接続要求を 5 個 (通常の
最大値) まで順番待ちさせるように命じている。これ以降の外部接続は拒否す
るのだが、コードが適切に書かれていれば、それで十分すぎるほどだ。

よし、「サーバーソケット」ができて、80 番ポートで耳を澄ましているとこ
ろまで来た。では、ウェブサーバのメインループに入ろう:

   while 1:
       #accept connections from outside
       (clientsocket, address) = serversocket.accept()
       #now do something with the clientsocket
       #in this case, we'll pretend this is a threaded server
       ct = client_thread(clientsocket)
       ct.run()

このループには実際のところ、3 通りの一般的な動作方法がある -
"clientsocket" を扱うようにスレッドを割り当てたり、"clientsocket" を扱
う新しいプロセスを作ったり、あるいはノンブロッキングソケットを使うよう
にアプリを作り直して "select" で「サーバ」ソケットとアクティブな
"clientsocket" の間を多重化したりするのだ。最後のについてはまた後にし
よう。ここで理解しておくべき要点はこれだ: 以上が「サーバ」ソケットの仕
事の *すべて* である。データは一切送信しないし、受信しない。「クライア
ント」ソケットを生み出すだけ。我々のバインドされているホストとポートに
"connect()" してくる *他の* 「クライアント」ソケットに応える形で
"clientsocket" を作り、作るや否や、さらなる接続を聞きに戻っていくのだ
。このふたつの「クライアント」は、あとは勝手に喋っていればいい - 使う
ポートは動的に割り当てられ、会話が終わればリサイクルに廻される。


IPC
---

If you need fast IPC between two processes on one machine, you should
look into whatever form of shared memory the platform offers. A simple
protocol based around shared memory and locks or semaphores is by far
the fastest technique.

If you do decide to use sockets, bind the 「server」 socket to
"'localhost'". On most platforms, this will take a shortcut around a
couple of layers of network code and be quite a bit faster.


ソケットの利用
==============

はじめに憶えておくべきなのは、ウェブブラウザの「クライアント」ソケット
とウェブサーバの「クライアント」ソケットがまったく同じ種族だということ
だ。つまり、これは「ピア・トゥ・ピア」(1 対 1) の会話である。別の言い
方をすると、 *設計者として自分で会話のエチケット規則を決めなくてはいけ
ない* ということでもある。通常は、 "connect" してくるソケットが要求あ
るいは宣言をして会話を始める。だが、それはそう設計しただけのことだ -
ソケットの規則ではない。

さて、コミュニケーションに使う動詞は二組ある。 "send" と "recv" を使う
こともできるし、クライアントソケットをファイルっぽい種族に変形して
"read" と "write" を使っても良い。後者は Java のソケットの表現方法だ。
ここで詳しく語るつもりはないが、その場合はソケットも "flush" しなけれ
ばいけない、とだけ言っておく。これはバッファリングした「ファイル」なの
で、何かを "write" してすぐに返答を "read" するというのはよくある間違
いだ。間に "flush" を入れないと、要求がまだ出力バッファにあって永遠に
返事が来ない、という可能性がある。

さあ、ソケットの主要な難関に進もう -  "send" と "recv" はネットワーク
バッファに働きかけるものだ。だから、手渡したもの (や返してもらいたいも
の) を 1 バイトも残さず実際に処理してくれているとは限らない。一般的に
言って、 "send" はバッファが埋まるまで、"recv" はバッファが空になるま
で処理をして、そのバイト数を返す。メッセージが完全に処理されるまで繰り
返し呼び出すのは *自分の* 責任なのだ。

"recv" が 0 バイトを返したときは、向こう側が接続を閉じてしまった (また
は閉じようとしている途中) という意味だ。もうこの接続でデータを受け取る
ことはない。永遠にだ。ただ、データ送信は成功するかもしれない; これにつ
いてはあとで語ることにしよう。

HTTP のようなプロトコルでは、ひとつのソケットを1回の転送にしか使わない
。クライアントは要求を送り、返答を受ける。以上だ。これでソケットは破棄
される。だからこの場合、クライアントは受信 0 バイトの時点で返答の末尾
を検出することができる。

だが、以降の転送にもそのソケットを使い回すつもりなら、ソケットに EOT
(End of Transfer) など *存在しない* ことを認識する必要がある。もう一度
言おう: ソケットの "send" や "recv" が 0 バイト処理で返ってきたなら、
その接続は終わっている。終わって *いない* なら、いつまで "recv" を待て
ばいいかは分からない。ソケットは「もう読むものが (今のところ) ないぜ」
などと *言わない* のだから。このことを少し考えれば、ソケットの真実を悟
ることになるだろう: *メッセージは必ず固定長か* (うげぇ) *区切り文字を
使うか* (やれやれ) *長さ標識を付けておくか* (かなりマシ) *接続を閉じて
終わらせるかのいずれかでなければいけない* のだ。選ぶ権利と責任はまった
くもって自分にある (が、正しさの程度に違いはある)。

毎回接続を終わらせるのはイヤだとして、最も単純な解決策は固定長メッセー
ジだろう:

   class mysocket:
       '''demonstration class only
         - coded for clarity, not efficiency
       '''

       def __init__(self, sock=None):
           if sock is None:
               self.sock = socket.socket(
                   socket.AF_INET, socket.SOCK_STREAM)
           else:
               self.sock = sock

       def connect(self, host, port):
           self.sock.connect((host, port))

       def mysend(self, msg):
           totalsent = 0
           while totalsent < MSGLEN:
               sent = self.sock.send(msg[totalsent:])
               if sent == 0:
                   raise RuntimeError("socket connection broken")
               totalsent = totalsent + sent

       def myreceive(self):
           chunks = []
           bytes_recd = 0
           while bytes_recd < MSGLEN:
               chunk = self.sock.recv(min(MSGLEN - bytes_recd, 2048))
               if chunk == '':
                   raise RuntimeError("socket connection broken")
               chunks.append(chunk)
               bytes_recd = bytes_recd + len(chunk)
           return ''.join(chunks)

この送信コードは、ほぼあらゆるメッセージ通信スキームで使える - 文字列
を送るとき、Python なら長さを "len()" で見極めることができる (中に
"\0" が埋め込まれていても大丈夫)。難しくしているのは、おもに受信コード
である。 (なお、C でも事態はあまり悪くならないが、メッセージに "\0" が
埋め込まれていると "strlen" が使えないのは面倒だ。)

最も簡単な改良法は、メッセージの最初の一文字をタイプ標識にして、そのタ
イプで長さを決定するというものだ。この場合ふたつの "recv" があることに
なる - 一番目でその一文字 (だけじゃなくても可) を取って長さを調べ、二
番目でループして残りを取るのだ。あるいはもし区切り方式の道を行くのであ
れば、任意のサイズ (4096 か 8192 がネットワークバッファには最適なこと
が多い) で受信して区切り文字を走査していくことになる。

心に留めておくべき面倒な点がひとつ: 複数メッセージが次々に (何らかの返
事を待たずに) 返ってくることのある会話プロトコルなら、そして任意のサイ
ズを "recv" に渡しているなら、次のメッセージの冒頭部分まで読んでしまう
ことがあるかもしれない。そのときは、必要になるまで脇によけて、大切に保
管しておく必要がある。

メッセージ冒頭に長さを (たとえば 5 桁の数字で) 付けるのは、それよりも
さらに複雑になる。というのも、(信じられないかもしれないが) 一回の
"recv" で 5 文字を全部受け取ることができるとは限らないからだ。お遊びで
やっている間はごまかせても、高負荷ネットワークのもとでは、"recv" ルー
プをふたつ使わないコードは、あっと言う間にダメになってしまう - 一番目
は長さを見定める用で、二番目はデータ部分を受け取る用だ。うーむ、いやら
しい。さらにこのとき、"send" も一発で全部を出し切れるとは限らないこと
に気付くだろう。なお、今こうやって読んでいても、いつか誰もが痛い目を見
るのである!

紙面の都合および教育的配慮 (と著者の地位確保) のため、こうした改良は練
習問題として残しておく。さあ片付けてしまおう。


バイナリデータ
--------------

バイナリデータはまったく問題なくソケットに乗せられる。問題は、すべての
マシンで同じ形式を使っているわけではないことにある。たとえば Motorola
のチップなら 16 ビット整数の 1 という値をふたつの 16 進バイト列 00 01
で表現するが、Intel や DEC は逆バイトだ - 同じ 1 が 01 00 になるのだ。
ソケットライブラリは 16 ビットや 32 ビット整数の変換用コールを持ってい
る - "ntohl, htonl, ntohs, htons" である。」n」 は *network*、 「h」
は *host* を意味する。 「s」 は *short* で 「l」 は *long* だ。これら
のコールは、「ネットワーク並び = ホスト並び」なら何もしないが、マシン
が逆バイトならそれに合わせてぐるっと交換してくれる。

この 32 ビット時代、バイナリデータは ASCII 表現のほうが小さくなること
が多い。というのも、long なのに値が 0 ばっかりでたまに 1 だとかいうこ
とは驚くほど多いからだ。文字列なら 「0」 は 2 バイトなのに、バイナリは
4 バイトも喰う。もちろんこれは固定長メッセージには合わないが。さあ、ど
うする、どうする。


切断
====

厳密には、ソケットを "close" する前には "shutdown" することになってい
る。 "shutdown" は相手ソケットに対する報告であり、渡す引数によって「こ
れ以上こっちからは送らないけど、まだ聞いてるぜ」という意味になったり、
「もう聞かない。せいせいした!」だったりする。しかしほとんどのソケット
ライブラリは、このエチケットを怠るプログラマに慣れてしまって、通常
"close" だけで "shutdown(); close()" と同じことになる。だから大抵はわ
ざわざ "shutdown" しなくてもいい。

"shutdown" の効果的な使い方のひとつは、HTTP 風のやりとりだ。クライアン
トは要求を出してすぐに "shutdown(1)" する。これでサーバに、「クライア
ントは送信完了ですが、まだ受信可能です」と伝わる。サーバは 0 バイト受
信で 「EOF」 を検出することができる。要求を残さず受け取ったことにして
良いのだ。対してサーバは返答を送る。その "send" が成功したなら、クライ
アントは実際にまだ受信していたことになる。

Python はこの自動 shutdown をもう一歩進めて、ソケットが GC されるとき
に必要なら自動で "close" してくれると言っている。しかしこれに頼るクセ
をつけてはいけない。もしソケットが "close" せずに姿を消せば、相手ソケ
ットはこちらが遅いだけだと思ってハングしてしまうかもしれない。 *お願い
だから* 終わったらちゃんと "close" してくれ。


ソケットが死ぬと
----------------

Probably the worst thing about using blocking sockets is what happens
when the other side comes down hard (without doing a "close"). Your
socket is likely to hang. SOCKSTREAM is a reliable protocol, and it
will wait a long, long time before giving up on a connection. If
you’re using threads, the entire thread is essentially dead. There’s
not much you can do about it. As long as you aren’t doing something
dumb, like holding a lock while doing a blocking read, the thread
isn’t really consuming much in the way of resources. Do *not* try to
kill the thread - part of the reason that threads are more efficient
than processes is that they avoid the overhead associated with the
automatic recycling of resources. In other words, if you do manage to
kill the thread, your whole process is likely to be screwed up.


ノンブロッキングソケット
========================

ここまで理解してきたなら、もうソケットの仕組みについて必要なことはほと
んど知っていることになる。これからも同じコールを、ほぼ同じように使って
いくだけ、それだけだ。これをちゃんとやっていれば、そのアプリはだいたい
完璧であろう。

Python の場合、ノンブロッキングにするには "socket.setblocking(0)" を使
う。 C ならもっと複雑だ (一例を挙げると、BSD 方式の "O_NONBLOCK" およ
びほぼ違いのない POSIX 方式 "O_NDELAY" のどちらを選ぶか決めなくてはな
らなくて、後者は "TCP_NODELAY" とは全然別物だったりする) が、考え方は
まったく一緒だ。

構造上の大きな違いは、 "send", "recv", "connect", "accept" が何もしな
いで戻ってくるかもしれないという点である。選択肢は (当然ながら) いくつ
かある。返り値とエラーコードをチェックするという方法もある。が、発狂す
ること請け合いだ。信じないなら、いつかやってみるといい。アプリは肥大化
し、バグが増え、CPU を喰い尽くすだろう。だからそんな愚かな解法は飛ばし
て、正解に進もう。

"select" を使え。

C において "select" でコードを書くのはかなり面倒だが、Python なら造作
もない。しかし Python で "select" を理解しておけば C でもほとんど問題
なく書ける、という程度には似ている:

   ready_to_read, ready_to_write, in_error = \
                  select.select(
                     potential_readers,
                     potential_writers,
                     potential_errs,
                     timeout)

"select" に三つのリストを渡しているが、一番目にはあとで読みたくなるか
もしれないソケットすべて、二番目には書き込みたくなるかもしれないソケッ
トすべて、最後に (通常は空のままだが) エラーをチェックしたいソケットが
入っている。ひとつのソケットが複数にまたがってリストされても構わないこ
とを憶えておくと良い。なお、 "select" コールはブロックするが、時間制限
を与えることができる。これは、やっておいて損はない - 特に理由がなけれ
ば、かなり長い (たとえば 1 分とかの) 時間制限を付けておくことだ。

戻り値として、三つのリストが手に入る。それぞれには、実際に読めるソケッ
ト、書けるソケット、エラー中のソケットが入っていて、渡したリストの部分
集合 (空集合かもしれない) になっている。

出力のうち、readable リストにあるソケットについては、 "recv" がとりあ
えず *何か* を返すであろう、ということは史上最高度に確信できる。
writable リストも考え方は同じで、 *何か* は送れる。送りたいもの全体は
無理かもしれないが、 *何も* ないよりはマシだろう。 (実のところ、ふつう
に健康なソケットなら writable で返ってくることができる - それは外向き
ネットワークバッファに空きがあるというだけの意味しかないのだから)

「サーバ」ソケットは potential_readers リストに入れておこう。それが
readable リストに入って出てきたら、 "accept" は (ほぼ) 確実に成功する
はずだ。どこかへ "connect" するために作った新しいソケットは
potential_writers リストに入れる。それが writable リストに現れたら、接
続が成功している可能性は高いと言える。

One very nasty problem with "select": if somewhere in those input
lists of sockets is one which has died a nasty death, the "select"
will fail. You then need to loop through every single damn socket in
all those lists and do a "select([sock],[],[],0)" until you find the
bad one. That timeout of 0 means it won’t take long, but it’s ugly.

じつは "select" はブロッキングソケットにも便利に使える。それはブロック
するかどうかを見極める方法のひとつである - バッファに何かがあれば
readable として返ってくるのだ。しかしこれも、相手の用事がもう済んでい
るのか、それとも単に他のことで忙しいだけなのかを見極める役には立たない
。

**Portability alert**: On Unix, "select" works both with the sockets
and files. Don’t try this on Windows. On Windows, "select" works with
sockets only. Also note that in C, many of the more advanced socket
options are done differently on Windows. In fact, on Windows I usually
use threads (which work very, very well) with my sockets. Face it, if
you want any kind of performance, your code will look very different
on Windows than on Unix.


Performance
-----------

There’s no question that the fastest sockets code uses non-blocking
sockets and select to multiplex them. You can put together something
that will saturate a LAN connection without putting any strain on the
CPU. The trouble is that an app written this way can’t do much of
anything else - it needs to be ready to shuffle bytes around at all
times.

Assuming that your app is actually supposed to do something more than
that, threading is the optimal solution, (and using non-blocking
sockets will be faster than using blocking sockets). Unfortunately,
threading support in Unixes varies both in API and quality. So the
normal Unix solution is to fork a subprocess to deal with each
connection. The overhead for this is significant (and don’t do this on
Windows - the overhead of process creation is enormous there). It also
means that unless each subprocess is completely independent, you’ll
need to use another form of IPC, say a pipe, or shared memory and
semaphores, to communicate between the parent and child processes.

Finally, remember that even though blocking sockets are somewhat
slower than non-blocking, in many cases they are the 「right」
solution. After all, if your app is driven by the data it receives
over a socket, there’s not much sense in complicating the logic just
so your app can wait on "select" instead of "recv".
