[BlueLeaf1336]> PROGRAM> WinSock勉強会>

WinSockの基本 -- その1

historyTOP

2002/11/28:作成
2002/11/29:更新

Winsockの初期化TOP

ソケットは、使用する前に、オープンする必要がある。 これは、WSAStartupを使って行う。 Winsock.pasには次のように宣言されている。

{$EXTERNALSYM WSAStartup}
function WSAStartup(wVersionRequired: word;
                    var WSData: TWSAData): Integer; stdcall;
wVersionRequired: word
「プログラムが想定するバージョン」 Word型の上位バイトにマイナー、下位バイトにメジャーのバージョンをそれぞれ指定する。 たとえば、ver.1.1なら、MAKEWORD(1,1)のように指定する。 $0101でもよい。 ver.2.0だったら、MAKEWORD(0,2)なんでしょうね。多分。 ver.1.1って例題としてはもうひとつ。
var WSData: TWSAData
varとあるとおり、WSAStartupが設定して返してくる。 この、TWSADataは、Winsock.pasには下のように宣言されている。
戻り値
成功したら、0。失敗したらエラーコード。
type
  PWSAData = ^TWSAData;
  {$EXTERNALSYM WSAData}
  WSAData = record // !!! also WSDATA
    wVersion: Word;
    wHighVersion: Word;
    szDescription: array[0..WSADESCRIPTION_LEN] of Char;
    szSystemStatus: array[0..WSASYS_STATUS_LEN] of Char;
    iMaxSockets: Word;
    iMaxUdpDg: Word;
    lpVendorInfo: PChar;
  end;
  TWSAData = WSAData;
wVersion
「プログラムが想定するバージョン」。 $0101でなければエラーにしてしまってよいようです。
wHighVersion
「対応できる最高のバージョン」。 それを決めるのが、WSAStartupっておかしくないか?
szDescription
備考みたいなもの。
szSystemStatus
備考みたいなもの。
iMaxSockets
使用できる最大のソケット数。Win95標準のだと256個。 サーバーを作るときに「クライアントとつなぎっぱなしにしてはいけない」。
iMaxUdpDg
UDPソケットで扱える最大のバイト数。
lpVenderInfo
ベンダー固有情報。PCharになっているが、文字列が入っているとは限らない。

以上から、ソケットを「開けるだけ」なら、こんな感じ。

function tzWSAStartup: integer;
var
    ad: TWSAData;
begin
    Result := WSAStartup($0101, WSAData);
end;
TWSADataの中身見ても、時々刻々変わるわけでもないので、面白くなさそう。 よって、TWSADataをローカル変数に叩き込んで、使い捨てにしてしまう。

ただ、戻り値をどうするかが微妙。 戻さずに、エラーだけ表示して、Application.Terminateするか。 どうでもいいような引数を隠蔽するという意味ではそこそこな気もする。

Winsockの初期化テストTOP

フォームにボタンを1個作って、さっきの関数を貼り付けて、ボタンクリックで関数を呼びます。

(略)
implementation uses Winsock; {$R *.dfm} function tzOpenSocket: integer; var ad: TWSAData; begin Result := WSAStartup($0101, ad); end; procedure TForm1.Button1Click(Sender: TObject); begin ShowMessage(IntToStr(tzOpenSocket)); end; end.
結果は、0。何回かやってみるけども0。って、何回もやってもいいんだろうか。 ここで、あえて、エラーを起こさせてみることにする。方法は、
Result := WSAStartup($0102, ad);
こんな感じで。...関係ねーよ。0がかえってきてる。いろいろ試してみよう。

wVersion-RequiredWSA-StartupGet-LastErrorWSAGet-LastErrorSysErrorMessage(WSAGetLastError)
$10001009255アクセスが拒否されました。
$20001009255アクセスが拒否されました。
$29001009255アクセスが拒否されました。
$0099000この操作を正しく終了しました。
$9999000この操作を正しく終了しました。

あれだ。メジャーバージョンが「0」だとだめで、「0以外」だと何でもとおってる。 適当か?ひょっとしてそういう問題じゃないのかも。 「プログラムが想定するバージョン」だから、Winsock側は知ったこっちゃないのかも。 無視しといていいのだろうか。

とりあえず、「ソケットをオープンできた」というところで今日は終わり。

Winsockの解放TOP

2002/11/29

開けたものは閉じる。 ソケットを閉じる方法は、WSACleanupを呼ぶだけ。 Winsock.pasには次のように宣言されている。

{$EXTERNALSYM WSACleanup}
function WSACleanup: Integer; stdcall;

Winsockの解放テストTOP

function tzCloseSocket: integer;
begin
    Result := WSACleanup;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
    tzCloseSocket;
    ShowMessage(IntToStr(GetLastError));                // --1
//    ShowMessage(SysErrorMessage(GetLastError));       // --2
//    ShowMessage(IntToStr(WSAGetLastError));           // --1'
//    ShowMessage(SysErrorMessage(WSAGetLastError));    // --2'
end;
こんな感じで、昨日のコードの続きに書く。 で、ソケットのオープンをせずに、いきなり、Button2を押してみるとこんな感じ。

GetLastError10093
SysErrorMessage(GetLastError)アプリケーションが WSAStartup を呼び出していないか、または WSAStartup が失敗しました。
WSAGetLastError10093
SysErrorMessage(WSAGetLastError)アプリケーションが WSAStartup を呼び出していないか、または WSAStartup が失敗しました。

逆に、ちゃんとソケットをオープンしてから、Button2を押すと、こんな感じ。

GetLastError0
SysErrorMessage(GetLastError)この操作を正しく終了しました。
WSAGetLastError0
SysErrorMessage(WSAGetLastError)この操作を正しく終了しました。

成功した場合は、返り値が、0。エラーなら、10093。 これは、SOCKET_ERRORらしい。

とりあえず、これで、開け閉めできるようになった。

エラーを調べるTOP

ここまで、エラーを調べるのに、 GetLastErrorWSAGetLastErrorSysErrorMessage を使ってきたが、WSAGetLastError以外は、WinSock.pasに、 残りの2つは、SysUtils.pasにある。 WSAGetLastErrorの宣言は、これ。

{$EXTERNALSYM WSAGetLastError}
function WSAGetLastError: Integer; stdcall;
気をつける必要があるのは、どちらも(*GetLastError)呼び出したときに、 エラーをクリアすることである。 つまり、2回呼び出したら1回目はエラーと出ても、2回目は成功したことになる。 なので、さっきのButton2Clickの中では、エラー調査はどれか1行にしてたんである。

あと、気になるのは、GetLastErrorWSAGetLastErrorのどちらを使っても おんなじ答えを返してくるということで、これどうなんだろう。それに、WSAGetLastError の存在を知らないSysErrorMessageで、毎回うまくいくんだろうか。 とりあえず、これからは、WSAGetLastErrorだけで行くことにする。

EOFTOP