2 What is a socket?

2 What is a socket? #

“ソケット"という言葉をよく耳にしますが、そもそも"ソケット"とは何なのでしょうか?それは、標準的な Unix のファイルディスクリプタを使って他のプログラムと会話するための方法です。

なんと?

Ok— Unix のハッカーが “Unix では何でもファイルなんだ!“と言ったのを聞いたことがあるかもしれません。その人が言っているのは、Unix のプログラムが何らかの I/O を行うとき、ファイル記述子に対して読み書きを行うという事実のことかもしれません。ファイルディスクリプタは、単純に、開いているファイルに関連する整数です。しかし、このファイルは、ネットワーク接続、FIFO、パイプ、ターミナル、ディスク上のファイルなど、あらゆるものになり得ます(ここが重要)。Unix ではすべてがファイルなのです!だから、インターネット上で他のプログラムと通信したいときは、ファイル記述子を介して行うことになるんだ。と思ってください。

“ネットワーク通信のためのファイルディスクリプタはどこで手に入るのですか、お利口さん?“というのが、今あなたが考えている最後の質問でしょうが、とにかくそれに答えてあげましょう。あなたは socket() システムルーチンを呼び出すのです。このルーチンはソケットディスクリプタを返すので、それを使って send()recv() ( man send, man recv) という特別なソケットコールを使って通信を行います。

“でもね!“あなたは今頃、そう叫んでいるかもしれません。“ファイルディスクリプタなら、どうしてネプチューンの名において、通常の read()write() の呼び出しでソケットを通して通信できないんだ?“と。短い答えは、“できる!“です。もっと長い答えは、“できるけど、send()recv() はデータ転送をより大きく制御できる “です。

次は何?どうでしょう、ソケットにはいろいろな種類がありますね。DARPA インターネットアドレス (インターネットソケット)、ローカルノード上のパス名 (Unix ソケット)、CCITT X.25 アドレス (X.25 ソケット、無視しても大丈夫)、そしておそらくあなたが実行する Unix のフレーバーに応じて他の多くの種類があります。この文書では、最初の"インターネットソケット"のみを扱います。

2.1 Two Types of Internet Sockets #

これは何?インターネットソケットには2種類ある?そうです。まあ、違うけど。嘘です。もっとあるんだけど、怖がらせたくなかったんだ。 ここでは2種類しか話しません。ただし、この文章では、“Raw Sockets” も非常に強力なので、ぜひ調べてみてくださいと言うつもりです。

わかったよ、もう。この2つのタイプは何ですか?一つは"ストリームソケット”、もう一つは"データグラムソケット"で、以下、それぞれ “SOCK_STREAM” “SOCK_DGRAM” と呼ぶことがあります。データグラムソケットは"コネクションレス型ソケット"と呼ばれることもあります 。(ただし、本当に必要であれば connect()' を使用することができます。後述の connect() を参照してください)。

ストリームソケットは、信頼性の高い双方向接続の通信ストリームです。ソケットに2つのアイテムを “1, 2” という順序で出力すると、反対側にも “1, 2” という順序で届きます。また、エラーも発生しません。実際、私はエラーフリーであることを確信しています。もし、そうでないと主張する人がいたら、耳に指を突っ込んで"ララララ"と唱えてやりたいくらいだ。

何がストリーム・ソケットを使うのでしょうか?さて、皆さんは telnet というアプリケーションをご存知でしょうか?あれはストリームソケットを使っているんだ。あなたが入力した文字は、すべて入力した順番に到着する必要がありますよね?また、Webブラウザは HTTP(Hypertext Transfer Protocol) を使っていますが、これはストリームソケットを使ってページを取得します。実際、80番ポートで Web サイトに telnet して、"GET / HTTP/1.0” と入力してリターンを2回押すと、HTML がダンプされて戻ってきますよ。

もし telnet がインストールされておらず、インストールもしたくない場合、あるいは telnet がクライアントとの接続にうるさい場合、ガイドには telnot という telnet に似たプログラムが付属しています。これは、このガイドで必要なものすべてに対してうまく機能するはずです。(なお、telnet は実際には spec’d networking protocol であり、telnot はこのプロトコルを全く実装していません)。

ストリームソケットは、どのようにしてこの高いレベルのデータ伝送品質を実現しているのでしょうか。 それは、“TCP” として知られる"伝送制御プロトコル”(TCP の詳細については RFC 793 を参照)というプロトコルを使用しているからです。TCP はデータが順次、エラーなく到着することを確認します。“TCP” は “TCP/IP” の半分で、“IP” は “Internet Protocol”( RFC 791 を参照)の略だと聞いたことがあるかもしれません。IP は主にインターネット・ルーティングを扱い、一般にデータの完全性には責任を持ちません。

かっこいい。データグラムソケットについてはどうでしょうか?なぜコネクションレス型と呼ばれるのでしょうか?どうなっているんだ?なぜ信頼性が低いのでしょうか?データグラムを送ると、それが届くかもしれません。データグラムを送信すると、それは到着するかもしれません。もし到着すれば、パケット内のデータはエラーフリーです。

データグラムソケットもルーティングに IP を使いますが、TCP は使わず、“User Datagram Protocol”、つまり “UDP” を使います( RFC 768 を参照)。

なぜコネクションレスレスなのか?まあ、基本的には、ストリームソケットのようにオープンな接続を維持する必要がないからです。パケットを作り、その上に宛先情報を含む IP ヘッダを貼り付け、送信するだけでいいのです。コネクションは必要ありません。一般的には、TCP スタックが利用できないときや、パケットをいくつか落としても宇宙の終わりを意味しないときに使用されます。サンプルアプリケーション: tftp (FTP の弟分のようなファイル転送プロトコル)、dhcpcd (DHCP クライアント)、マルチプレイヤーゲーム、ストリーミングオーディオ、ビデオ会議、などなど。

“ちょっと待った!tftpdhcpcd はバイナリアプリケーションをあるホストから別のホストに転送するために使われるんだ!アプリケーションが到着したときに動作することを期待するならば、データが失われることはありえない!これはどんな黒魔術なんだ?”

さて、私の人間の友人である tftp やそれに類するプログラムは、UDP の上に独自のプロトコルを載せています。たとえば、tftp プロトコルは、送信されたパケットごとに、受信者は"受け取ったよ!“というパケットを送り返さなければならない、と言っています。というパケット(“ACK” パケット)を送り返さなければなりません。元のパケットの送信者は、例えば5秒間返信がない場合、最終的に ACK を得るまでパケットを再送信することになります。この確認手続きは、信頼性の高い SOCK_DGRAM アプリケーションを実装する際に非常に重要です。

ゲーム、オーディオ、ビデオなどの信頼性の低いアプリケーションでは、ドロップしたパケットを無視するか、あるいは巧みに補うようにします。(Quake プレイヤーは、この効果の発現を呪われたラグという専門用語で知っていることでしょう。 この場合の"呪われた"という単語は、非常に不敬な発言を意味します)。

なぜ信頼性の低い基礎プロトコルを使うのでしょうか?理由は2つ、速度とスピードです。何が無事に到着したかを追跡し、順序立てて確認したりするよりも、発射して忘れる方がずっと速いのです。チャットメッセージを送るなら、TCP は素晴らしいです。世界中のプレイヤーの位置情報を毎秒40件送るなら、1件や2件が落ちてもそれほど問題ではないので、UDP は良い選択だと思います。

2.2 Low level Nonsense and Network Theory #

先ほどプロトコルの階層化について触れましたので、そろそろネットワークが実際にどのように動作するのか、そして SOCK_DGRAM パケットがどのように構築されるのかについて、いくつかの例を挙げて説明しましょう。 実際のところ、このセクションは読み飛ばしても大丈夫でしょう。しかし、良い背景にはなります。

[Encapsulated Protocols Diagram]
データのカプセル化

子供たちよ、データカプセル化について学ぶ時間だ!これはとても重要なことです。あまりに重要なので、このチコステでネットワークの授業を受けると、このことを学ぶことになるかもしれません ;-). 基本的にはこうです:パケットが生まれ、パケットは最初のプロトコル(例えば TFTP プロトコル)によってヘッダー(まれにフッターも)でラップ(“カプセル化”)され、次のプロトコル(例えば UDP)によって全体(TFTP ヘッダーも含む)が再びカプセル化され、さらに次のプロトコル(IP)によってカプセル化され、ハードウェア(物理)層(例えば Ethernet)の最終プロトコルによって再びカプセル化されます。

他のコンピュータがパケットを受信すると、ハードウェアがイーサネットヘッダを、カーネルが IP と UDP ヘッダを、TFTP プログラムが TFTP ヘッダを取り除き、ようやくデータを手に入れることができます。

これでやっと悪名高いレイヤードネットワークモデル(通称 “ISO/OSI”)について語れるようになりました。このネットワークモデルは、他のモデルに比べて多くの利点を持つネットワーク機能のシステムを記述しています。例えば、データが物理的にどのように転送されるか(シリアル、シンイーサネット、AUI、何でも)を気にせずに、全く同じソケットプログラムを書くことができます。実際のネットワークハードウェアやトポロジーは、ソケットプログラマにとって透過的です。

さっそくですが、本格的なモデルのレイヤーを紹介します。 ネットワーククラスの試験のために覚えておいてください。

  • アプリケーション層
  • プレゼンテーション層
  • セッション層
  • トランスポート層
  • ネットワーク層
  • データリンク層
  • 物理層

物理層は、ハードウェア(シリアル、イーサネットなど)です。アプリケーション層は物理層から想像できる限り離れたところにあり、ユーザーがネットワークと相互作用する場所です。

さて、このモデルは、本当にやろうと思えば、自動車の修理ガイドとして使えるほど一般的なものです。Unix とより整合性のあるレイヤーモデルは、次のようなものでしょう。

  • アプリケーション層 (telnet, ftp, etc.)
  • Host-to-Host トランスポート層 (TCP, UDP)
  • インターネット層 (IP and routing)
  • ネットワークアクセス層 (Ethernet, wi-fi, or whatever)

この時点で、これらのレイヤーが元のデータのカプセル化に対応していることがお分かりいただけたと思います。

シンプルなパケットを作るのに、どれだけの労力が必要なのか、おわかりいただけたでしょうか?じぇじぇじぇ!そして、"cat” を使って自分でパケットヘッダを入力しなければならないのです!冗談です。ストリームソケットでやるべきことは、データを send() することだけです。データグラムソケットでは、あなたが選んだメソッドでパケットをカプセル化し、sendto() で送り出すだけでいいのです。カーネルはあなたのためにトランスポート層とインターネット層を構築し、ハードウェアはネットワークアクセス層を構築します。ああ、現代の技術ですね。

というわけで、ネットワーク理論についての簡単な解説を終わります。そうそう、ルーティングについて言いたいことを全部言うのを忘れていました:何もありません!(笑)。その通り、全く話すつもりはありません。ルータはパケットを IP ヘッダに分解し、ルーティングテーブルを参照し、ブラブラブラブラ。もし本当に気になるなら、 IP RFC をチェックしてみてください。もしあなたがそれについて学ぶことがなければ、まあ、あなたは生きていくでしょう。