こける Wired-Winsockを使ってみようぜ-5.よくあるエラー'97/12/07

5.よくあるエラー


今回は、予定を変えて「よくあるエラー」の回にします。
なぜかって?
前回までで一つもエラーコードの説明をしなかったので、実際にプログラムを組むとなるとエラーが発生したとき分からないじゃないですか。
で、まぁ反省してエラーコードの回をもうけようかなと。(^^;;

エラーが発生したとして、その詳細情報を取得する関数がこれ。
function WSAGetLastError:Integer;
返り値はこの関数を呼び出す前までに発生したエラーのエラーコードです。
これを呼び出したからといってエラーコードは消えません。なので何回呼び出しても大丈夫ですが、逆にこの関数だけでエラーを発見することはできません。エラーコードが返ってきても、ずいぶん前に発生したやつかもしれませんので。
基本的にエラーを発見したらすぐにこの関数を呼び出して原因を調べましょう。
他のwinsockAPIを呼び出すとエラーが上書きされちゃいますよ。

エラーが発生しても、この関数でエラーコードが分からないものもあります。
一つはWSAStartUpです。
WSAStartUpが成功しないとWSAGetLastErrorを含むwinsockAPIを呼び出すことができませんから仕方ありません。
WSAStartUpは、その返り値そのものがエラーコードです。
エラーコードの体系はWSAGetLastErrorと同じです。

他には、非同期型の使い方でその結果がエラーしているときです。
非同期型の説明は「固まらない住所調べ」までお待ちください。
この時は、メッセージの引数としてエラーコードが示されています。

どちらもエラーしていないとき、つまり成功したときは0です。

エラーコードのシンボルはwinsock.pasで定義されています。WSAEなんとかがそうです。

さて、エラーコード体系ですが、詳しくはwinsock.pasでも見ていただくとして、ここでは代表的なやつだけ紹介します。
そうそう、エラーコードのシンボルだけではわかりにくいでしょう。Program FilesのページにあるKTcpユニットをダウンロードして、その中のエラーコードの文字列化関数SockErrorStringのソースコードをご覧ください。
テーブルを使って変換しているのですが、そのテーブルの文字列を見れば少しは助けになるでしょう。
ここでは、その文字列も付記します。

  1. WSAEINTR 中止命令により中断しました
    これは、同期型ソケットのsendとかrecvを無理矢理中断した場合に出てくるエラーコードです。無理矢理止めない限り出てきません。

  2. WSAEINVAL パラメータが解釈できません
    バグった時に出てきます。
    無茶な引数を渡したときに出てくるエラーです。

  3. WSAEWOULDBLOCK 操作がブロックされます
    これは「非同期型」の使い方をしたときに見るやつです。
    実際には受信していない状態でrecvを呼び出した場合、同期型なら受信するまでrecvの中から返ってきませんが、非同期型ならこのエラーになるわけです。
    connectやsendなどのAPIを非同期型で使っているときも出てきます。
    非同期型で使っているときは、これはエラーというより正常な状態ですね。
    非同期型のconnectは逆に「成功」する事なんて無いでしょう。

  4. WSAEADDRINUSE アドレスがすでに使用中です
    サーバ側で発生するエラーです。
    一つのコンピュータには同じポートを持つアプリケーション2つは存在できません。
    それが発生したときです。
    よくあるのはソケットを閉じてすぐに同じポートでソケットを開設しようとしたときに発生するパターンです。
    closesocketしても数分間は裏でこっそりそのソケットは生きていたりします。
    このため、同じポートですぐにソケットを開設すると、このこっそり生きているソケットと同じポートになってしまうため、このエラーが発生します。

  5. WSAETIMEDOUT 接続タイムアウトが発生しました
    connectで発生するエラーです。
    要するに接続を待っている「コンピュータ」はいなかったってことです。
    恐らくサーバとして指定したマシンが落ちているんでしょう。
    ひょっとしたらネットワークに異常があって応答できないだけかもしれませんが。

  6. WSAECONNREFUSED 接続が拒否されました
    これまたconnectで発生するエラーです。
    この時は接続を待っている「アプリケーション」がいなかったのです。
    コンピュータは立ち上がっているけど、アプリケーションが立ち上がっていません。

  7. WSANO_DATA 見つかりません
    gethostbynameやgethostbyaddr、その非同期型であるWSAASyncGetHostByNameやWSAAsyncGetHostByAddrで発生するエラーです。
    要するに「そんなホストは見つからない」といわれているわけで、ユーザのホスト名入力ミスでしょう。
    WSAAsyncGetHostByNameやWSAAsyncGetHostByAddrの場合は、結果がメッセージとして飛んできた時に引数としてこのエラーコードが渡されます。WSAGetLastErrorではこのエラーにはなりません。

  8. WSAECONNRESET ピア側での接続がリセットされました
    通信している相手が強引に接続を断ったのですね。
    普通はrecvの返り値が0になるとか、非同期型ならFD_CLOSEのメッセージが飛んでくるとかするのですが、相手が強引にソケットをクローズした場合にはこういうエラーが発生することもあります。
大体こんなとこでしょうか。
Win3.1ではWSAEINPROGRESSとかも見ましたけど、Win95になってから見たエラーはこのぐらいです。
ここに出てきているエラーぐらいなら、プログラム側でも処理できるでしょう。
WSANO_DATA、WSAETIMEDOUT、WSAECONNREFUSEDなんてエラー表示するぐらいしかありませんが。
WSAEADDRINUSEも時間待って再度ソケットを開設するのは危険ですね。
裏で生きているソケットとポートがバッティングしたのなら待てばよいのですが、別のアプリケーションとバッティングしているといつまで経ってもWSAEADDRINUSEですしね。
しかし、分かってやってるぶんにはいいかな。
自分が直前までそのポートでソケットを使っていて、再接続できるまでのチェックとして用いるのなら。

ここで紹介しなかった他のエラーは、それこそSockErrorStringを使ってエラー表示するぐらいでしょうか。中にはバグった時にしかお目見えしそうに無いエラーもあります。

今回はサンプルプログラムがありません。
KTcpユニットをダウンロードしてください。SockErrorString関数が使っているテーブルCWinSockErrorStrがそれにあたるかな?

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