[BlueLeaf1336]> PROGRAM> WinSock勉強会>
| history | TOP |
2002/11/28:作成
2002/11/29:更新
| Winsockの初期化 | TOP |
ソケットは、使用する前に、オープンする必要がある。 これは、WSAStartupを使って行う。 Winsock.pasには次のように宣言されている。
{$EXTERNALSYM WSAStartup}
function WSAStartup(wVersionRequired: word;
var WSData: TWSAData): Integer; stdcall;
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;
以上から、ソケットを「開けるだけ」なら、こんな感じ。
function tzWSAStartup: integer;
var
ad: TWSAData;
begin
Result := WSAStartup($0101, WSAData);
end;
TWSADataの中身見ても、時々刻々変わるわけでもないので、面白くなさそう。
よって、TWSADataをローカル変数に叩き込んで、使い捨てにしてしまう。
ただ、戻り値をどうするかが微妙。 戻さずに、エラーだけ表示して、Application.Terminateするか。 どうでもいいような引数を隠蔽するという意味ではそこそこな気もする。
| Winsockの初期化テスト | TOP |
フォームにボタンを1個作って、さっきの関数を貼り付けて、ボタンクリックで関数を呼びます。
(略)結果は、0。何回かやってみるけども0。って、何回もやってもいいんだろうか。 ここで、あえて、エラーを起こさせてみることにする。方法は、
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.
Result := WSAStartup($0102, ad);こんな感じで。...関係ねーよ。0がかえってきてる。いろいろ試してみよう。
| wVersion-Required | WSA-Startup | Get-LastError | WSAGet-LastError | SysErrorMessage(WSAGetLastError) |
|---|---|---|---|---|
| $1000 | 10092 | 5 | 5 | アクセスが拒否されました。 |
| $2000 | 10092 | 5 | 5 | アクセスが拒否されました。 |
| $2900 | 10092 | 5 | 5 | アクセスが拒否されました。 |
| $0099 | 0 | 0 | 0 | この操作を正しく終了しました。 |
| $9999 | 0 | 0 | 0 | この操作を正しく終了しました。 |
あれだ。メジャーバージョンが「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を押してみるとこんな感じ。
| GetLastError | 10093 |
|---|---|
| SysErrorMessage(GetLastError) | アプリケーションが WSAStartup を呼び出していないか、または WSAStartup が失敗しました。 |
| WSAGetLastError | 10093 |
| SysErrorMessage(WSAGetLastError) | アプリケーションが WSAStartup を呼び出していないか、または WSAStartup が失敗しました。 |
逆に、ちゃんとソケットをオープンしてから、Button2を押すと、こんな感じ。
| GetLastError | 0 |
|---|---|
| SysErrorMessage(GetLastError) | この操作を正しく終了しました。 |
| WSAGetLastError | 0 |
| SysErrorMessage(WSAGetLastError) | この操作を正しく終了しました。 |
成功した場合は、返り値が、0。エラーなら、10093。 これは、SOCKET_ERRORらしい。
とりあえず、これで、開け閉めできるようになった。
| エラーを調べる | TOP |
ここまで、エラーを調べるのに、 GetLastError、WSAGetLastError、SysErrorMessage を使ってきたが、WSAGetLastError以外は、WinSock.pasに、 残りの2つは、SysUtils.pasにある。 WSAGetLastErrorの宣言は、これ。
{$EXTERNALSYM WSAGetLastError}
function WSAGetLastError: Integer; stdcall;
気をつける必要があるのは、どちらも(*GetLastError)呼び出したときに、
エラーをクリアすることである。
つまり、2回呼び出したら1回目はエラーと出ても、2回目は成功したことになる。
なので、さっきのButton2Clickの中では、エラー調査はどれか1行にしてたんである。
あと、気になるのは、GetLastError、WSAGetLastErrorのどちらを使っても おんなじ答えを返してくるということで、これどうなんだろう。それに、WSAGetLastError の存在を知らないSysErrorMessageで、毎回うまくいくんだろうか。 とりあえず、これからは、WSAGetLastErrorだけで行くことにする。
| EOF | TOP |