こける Wired-Winsockを使ってみようぜ-1.Winsockの基礎知識 '97/11/16

1.Winsockの基礎知識

ネットワークプログラムを作る、それもインターネット等で使えるTCP/IPが扱いたい、となるとWindowsではWinsockを使うのが一番です。
Winsockは、Windows95/NTではネットワークAPIとしてWindowsAPIの一部を構成しています。
Windows3.1でも、「Winsock準拠」のネットワークドライバがあればWinsockが使えます。


サーバーとクライアント
ネットワークプログラムを作るんですが、さてどのような物をイメージしますか?
ぱっと思い付くのは、「Webブラウザ」とか「電子メール」の類でしょうか。「FTP」や「telnet」かもしれませんね。
今あげたプログラムは、「ネットワークにつながった別のコンピュータに何かを頼む」タイプのプログラムです。
「Webブラウザ」はURLで指定されたコンピュータを相手にホームページとして作成されている情報を読みだそうとするものですし、「電子メール」はSMTPサーバやPOPサーバを相手にそこにe-mail情報を書き込んだり、溜まっているe-mail情報を読み出したりするものです。(電子メールは全世界を相手にしますが、「電子メールプログラム」は単にSMTPサーバとPOPサーバを相手にしているだけです。POPサーバやSMTPサーバが全世界を相手にしてくれます。)
この時のイメージは「電話」に近いものです。
サービスのあるコンピュータに電話をかけて、ホームページを読み出したり、電子メールを送って欲しいと伝えたり。
ということは、「電話を待っているコンピュータ(プログラム)」が存在するわけです。
普通私たちが直接扱うネットワークプログラムは、「電話をかけてサービスを要求する」プログラムですね。
このように、自分からサービスのあるコンピュータをしていしてサービスを要求するプログラムを「クライアントプログラム」といいます。
逆に「クライアントプログラムからの要求を待っている」プログラムを「サーバプログラム」といいます。
電話と条件も結構似てるんですよ。クライアント側は「サーバのことを知ってないといけないけど、自分のは知らなくていい。」とかね。
既存のサービスを受けるためのプログラム-例えば「Webブラウザ」とか「電子メール」プログラム-を作るならクライアントプログラムさえ作ればよいのです。
しかし独自のサービス、例えば自作のネットワークゲーム等、を作る場合は、「サーバープログラム」と「クライアントプログラム」の両方を作らなければなりません。
もちろん、既存のサービスを受けるプログラムでもその相手をしてくれるサーバを確保してないと使えないわけですが。
IPアドレス
インターネットでは、コンピュータ同士がIPを使って通信を行っています。
IPすなわち「インターネットプロトコル」です。このIPで使用するアドレスが「IPアドレス」です。
IPはコンピュータ同士の通信、だからIPアドレスが表すのもコンピュータです。
IPアドレスは4Byteの数字で表します。
通常1Byteづつ10進数で表し、バイトの区切りを'.'で表します。たとえば"127.0.0.1"です。
この表現方法を「ドット付き10進数」といいます。
しかし、こんなIPアドレスを人間は覚えてられません。名前の方が覚えやすいのです。
で、通常コンピュータに名前を付けます。この名前とIPアドレスが相互に変換できれば人間は名前の方を指定できます。
このIPアドレスに変換可能なコンピュータの名前を「ホスト名」といいます。自分のコンピュータの名前は「ローカルホスト名」です。
winsockAPIには、このIPアドレスとホスト名の相互変換を行うものがあります。
そして、自分のローカルホスト名を取得するAPIもあります。
PPP接続の場合、接続するたびにIPアドレスもホスト名も変わります。
ホスト名やIPアドレスは接続時点でプロバイダによってあいているものが割り付けられるのです。
そのはずなんですが、winsockAPIを使ってローカルホスト名を取得してみるといつも同じローカルホスト名が出てきます。
それも[コントロールパネル]-[ネットワーク]-[ユーザ情報]-[コンピュータ名]と同じです。
プロバイダが付けたホスト名は?どうもWindows95がローカルホスト名に関して細工を行っているようです。
なのでwinsockAPIを使ってローカルホスト名を取得してもインターネット上で通用するホスト名は取得できません。
しかし、このローカルホスト名をIPアドレスに変換すると、ちゃんとインターネットで通用するIPアドレスが取得できます。

IPアドレスにはいくつかの特別な番号があります。
通常のIPアドレスがコンピュータの名前みたいなもの(どちらかというと住所ですが)だとするとこちらは代名詞のようなもの。
INADDR_ANY (0.0.0.0) 誰でもいいから
INADDR_LOOPBACK (127.0.0.1) 自分自身(というか、ネットワークに出さずに折り返し)
INADDR_BROADCAST (255.255.255.255) ネットワークに繋がっている全コンピュータ
INADDR_NONE (255.255.255.255) 存在しない
これらのIPアドレスが割り付けられるコンピュータは存在しません。
INADDR_ANYとINADDR_NONEはこれからしょっちゅう使うことになります。
サーバプログラムが通信相手を指定する場合、「誰でもいいから」なのでINADDR_ANY。
クライアントがサーバを探すとき、エラーすると「存在しない」のでINADDR_NONEです。
INADDR_BROADCASTとINADDR_NONEが同じ番号になっていますが、これは状況によりどちらになるか変わります。
普通、winsockAPIを呼び出した結果が255.255.255.255ならINADDR_NONE、存在しない=失敗ですし、winsockAPIにコンピュータを指定するために渡すのならINADDR_BROADCASTです。
INADDR_LOOPBACKは主にデバッグに使いますね。プロセス間通信にも使えますが、TCPを乗せてない環境だと動作しないかな。
ポート
IPはコンピュータ同士の通信を面倒見るもので、アプリケーション同士の通信は面倒見てくれません。
つまり、相手のコンピュータへデータを運んでくれますが、「どのアプリケーションへ運ぶのか」は関知外です。
このままでは「WebサーバとWebブラウザ」の通信には使えません。
で、「アプリケーション同士の通信」を面倒見てくれるものがいます。TCPです。
UDPってのもそうですが、ここでは説明を省略します。
TCPは「IPを使って」コンピュータまで運ばれてきたデータをそれぞれのアプリケーションに振り分けてくれます。
さて、IPはIPアドレスを使ってコンピュータを指定していましたが、TCPは何を使ってアプリケーションを指定するのでしょう?
これが「ポート」です。ポートはWORDの数値で表されます。
アプリケーションを指定するにはIPアドレス(どのコンピュータで実行されているか)とポート(どのアプリケーションか)を指定する必要があります。
ここではアプリケーションと言い切ってますが、実際には「アプリケーションの種類」です。
電子メールサーバ、Webサーバ、FTPサーバといったみんなが接続にくるようなアプリケーションサーバ(サービス)はその種類によって、決まったポートで待っています。例えば、電子メールの送信なら25番、受信が110番、FTPなら21番です。
もしあなたが独自のネットワークサービスプログラム、例えば自作のゲームとかを作るのならこれらの番号以外を選ばなければなりません。
5000番とかが良いでしょう。
TCPはポートとIPアドレスの両方を使って通信先を決定しますから、実際にはそのコンピュータで使われていないポートなら大丈夫なのですが、ネットワークゲームのポートが21番とかだと大変紛らわしいので止めましょうね。(^^;;
逆に電子メールプログラムやFTPプログラムを作りたいのなら、それぞれに定められた番号を使ってください。
ポートの「特別な番号」は0だけです。「あいているものを自動的に割り振れ」という意味になります。
サーバプログラムで「0」を選ぶと、その時々でポートが変わってしまい、クライアントが探せなくなりますので選ばないようにしてくださいね。

IPアドレスとポートで通信する相手を決めるということは一つのコンピュータに同じ種類のサービスを複数走らせることはできないという事になります。
一つのコンピュータに2つの「FTPサーバ」は載せられません。
少なくとも片方はFTPサービスで良く知られている21番を名乗ることはできないのです。
こう説明するとまるでサーバプログラムだけがポートを持っているようですが、実はクライアントにもポートがあります。
普通0を指定して「使っていない番号を割り振れ」とするので、気にしませんけども。
ストリームタイプ
TCPはIPを使ってアプリケーション同士の通信を面倒見てくれるのですが、他にもいろいろ手を出します。
たとえば、IPはエラーしないように努力はしますがエラーの発生を教えてくれません。送信した順番も守ってくれません。
これでは使いにくいので、TCPはエラーした部分を見つけて自動的に再送し補完してくれますし、順番も監視して送信した順番を守ってくれます。
しかし、「送信の区切りは受信側ではわからない」という性格を合わせ持ってしまいます。
つまり、送信側で「ABCDEF」「GHIJK」と2回に分けて送ったとしても、受信側では「ABC」「DEF」「GHIJK」の3回になるかもしれません。
この「区切りを持たない」という性格を「ストリームタイプ」といいます。
TCPを使う場合は、アプリケーション側でこの「区切り」を面倒見なければなりません。
この「区切りが無い」という性格は何かに似ていませんか?
バイナリファイルがそうですね。書き込むときに2回に分けて書き込んでも、読み込むときに1回で読んでしまうかもしれませんし、3回に分けて読むかもしれません。
テキストファイルもいわばバイナリファイルの一種なのですが、テキストファイルの場合はこの区切りに「改行文字」を使っています。
TCPでも区切りが欲しいときにはよく「改行文字」を使います。
しかし、これはアプリケーション同士で合意があった上のことです。
FTPやHTTP(Webブラウザ),SMTP(電子メール),POP3(電子メール受信)といったTCPを使ったプロトコルはみんな区切りとして「改行文字」を使っています。
TCP自身は「区切り」は一切面倒見てくれません。
ファイルの例でもテキストファイルをバイナリで開くことができますよね。
バイナリファイルとしてオープンして、その後改行文字で区切りとして、テキストになるのです。
TCPを使うネットワークプログラムを作成する場合には、アプリケーションでこの処理を入れないと区切りが判りません。
ソケット
これから使っていこうとするwinsockですが、こいつは通信の基本として「ソケット」を使います。
これは何かというと、ファイルを扱う場合の「ファイル」みたいなものです。
ファイルを書き込む場合の手順は大体以下のような感じですね。
  1. ファイルをファイル名とモードを指定してオープンする
  2. オープンできた「ファイル」にたいして書き込みを行う
  3. ファイルをクローズする。
winsockで送信する場合も似たようなものです。
クライアントの送信の場合は、以下のような処理になります。
  1. ソケットをオープンする。
  2. オープンしたソケットにたいし、サーバのIPアドレスとポートを指定して接続する。
  3. 接続できたソケットに対し、書き込み(送信)を行う。
  4. ソケットをクローズする。
接続の手間だけソケットの方が多いですね。
ファイルの場合はオープンするときにパラメータを指定していますが、ソケットの場合はオープンとパラメータの指定が別になっていると思ってもいいでしょう。
ネットワークバイトオーダと漢字コード
インターネットでは、いろいろなコンピュータがつながっています。 Windowsマシンばかりではないのです。
ということは、Windowsの常識が通用しないものも多いのです。
例えばWindowsで日本語を表すのに良く使う「シフトJIS」は、ほぼ異端扱いです。「Unicode」も駄目です。
日本語を表すのには「シフトJIS」や「Unicode」ではなく「JIS」を使う方が大抵は正解です。
ほらほら、電子メールプログラムを作ろうと思ったあなた、シフトJIS<->JIS変換プログラムを用意しといてくださいよ。
シフトJISのままインターネットに流さないように。(^^)
ま、自作ネットワークゲーム等の独自プロトコルの場合は何でも良いですけどね。
また数値は「ビッグエンディアン」がお約束です。
Windowsの走る「インテルCPU」は「リトルエンディアン」ですので注意しなければいけません。
これは何かというと、インターネットでは「一番大きな桁を先に送る」というお約束になっています。
しかし、インテルCPUは「小さな桁の方が先にある」のです。普通気が付かないかもしれませんが。
つまり、インテルCPUで「$1234」をメモリに格納すると、$34の次に$12が続きます。
でも、インターネットでは。$12を先に$34を後に送るお約束です。
ネットワーク上での数値の並びのお約束を「ネットワークバイトオーダ」といいます。「ネットワークバイトオーダ」は「ビッグエンディアン」なのです。
まとめ
長々と書いてきましたが、結局覚えといと欲しいのは以下の4点です。
  1. ネットワークゲームを組むには「サーバプログラム」と「クライアントプログラム」の2つのプログラムを作らなきゃいけない。
  2. そのプログラム用の「ポート」を決めなければいけない。
  3. 「サーバプログラム」の「ホスト名」か「IPアドレス」を「クライアントプログラム」で分かっていなければならない。
  4. 「ABCD」と送っても「ABCD」と受信するとは限らない。「AB」「CD」と受信しても困らないようにプログラムを組む。

次の話
[表紙] [Program Files] [オブジェクト指向異聞] [プログラム未整理知識] [Winsockを使ってみようぜ] [だべり] [What's New] [書いた奴] [リンク]