[BlueLeaf1336]> PROGRAM> WinSock勉強会>
history | TOP |
2002/12/04:作成
ソケット | TOP |
いよいよソケットを作る。で、ソケットとは何か?何だろう。 「こける」では、通信するための電話とある。媒介するもの。 音に対する空気にあたるものととらえてよいのだろうか。 光に対するエーテル(嘘)という感じだろうか。 とりあえず、問題が出てくるまでこの認識でいこう。
まず、ソケットを作る関数はこれ。
{$EXTERNALSYM socket} function socket(af, Struct, protocol: Integer): TSocket; stdcall;
まず、アドレスファミリーとは何か。WinSock.pasを開けてみよう。
...どっさり出てきた。
{ Address families. } {$EXTERNALSYM AF_UNSPEC} AF_UNSPEC = 0; { unspecified } {$EXTERNALSYM AF_UNIX} AF_UNIX = 1; { local to host (pipes, portals) } {$EXTERNALSYM AF_INET} AF_INET = 2; { internetwork: UDP, TCP, etc. } {$EXTERNALSYM AF_IMPLINK} AF_IMPLINK = 3; { arpanet imp addresses } {$EXTERNALSYM AF_PUP} AF_PUP = 4; { pup protocols: e.g. BSP } {$EXTERNALSYM AF_CHAOS} AF_CHAOS = 5; { mit CHAOS protocols } {$EXTERNALSYM AF_IPX} AF_IPX = 6; { IPX and SPX } {$EXTERNALSYM AF_NS} AF_NS = 6; { XEROX NS protocols } {$EXTERNALSYM AF_ISO} AF_ISO = 7; { ISO protocols } {$EXTERNALSYM AF_OSI} AF_OSI = AF_ISO; { OSI is ISO } {$EXTERNALSYM AF_ECMA} AF_ECMA = 8; { european computer manufacturers } {$EXTERNALSYM AF_DATAKIT} AF_DATAKIT = 9; { datakit protocols } {$EXTERNALSYM AF_CCITT} AF_CCITT = 10; { CCITT protocols, X.25 etc } {$EXTERNALSYM AF_SNA} AF_SNA = 11; { IBM SNA } {$EXTERNALSYM AF_DECnet} AF_DECnet = 12; { DECnet } {$EXTERNALSYM AF_DLI} AF_DLI = 13; { Direct data link interface } {$EXTERNALSYM AF_LAT} AF_LAT = 14; { LAT } {$EXTERNALSYM AF_HYLINK} AF_HYLINK = 15; { NSC Hyperchannel } {$EXTERNALSYM AF_APPLETALK} AF_APPLETALK = 16; { AppleTalk } {$EXTERNALSYM AF_NETBIOS} AF_NETBIOS = 17; { NetBios-style addresses } {$EXTERNALSYM AF_VOICEVIEW} AF_VOICEVIEW = 18; { VoiceView } {$EXTERNALSYM AF_FIREFOX} AF_FIREFOX = 19; { FireFox } {$EXTERNALSYM AF_UNKNOWN1} AF_UNKNOWN1 = 20; { Somebody is using this! } {$EXTERNALSYM AF_BAN} AF_BAN = 21; { Banyan } {$EXTERNALSYM AF_MAX} AF_MAX = 22;
AF_INETは一回使ったことがある。 gethostbyaddr(@ip, 4, AF_INET); ただし、このときは、Structという引数名に代入される値だった。 しかし今回は、Structが別にある。それはそれとして、今回も、これを使うらしい。
で、Structだが、「こける」では、TCP/IPの場合は、SOCK_STREAM を入れると書いてある。
ということは、ここには、下の5つのうちのどれかが入るようになっているわけだ。
{ Types } {$EXTERNALSYM SOCK_STREAM} SOCK_STREAM = 1; { stream socket } {$EXTERNALSYM SOCK_DGRAM} SOCK_DGRAM = 2; { datagram socket } {$EXTERNALSYM SOCK_RAW} SOCK_RAW = 3; { raw-protocol interface } {$EXTERNALSYM SOCK_RDM} SOCK_RDM = 4; { reliably-delivered message } {$EXTERNALSYM SOCK_SEQPACKET} SOCK_SEQPACKET = 5; { sequenced packet stream }
さらに、protocolだが、おそらく、 getprotobynameのところで使った、IPPROTO_**が入ると思われる。ただし、0(=IPPROTO_IP)を指定することで、自動割り当てされるらしい。
そして、最も重要な、TSocketという型で作られたソケットが戻ってくる。 TSocketがどんな内容かを調べてみると、こんなの。
type { The new type to be used in all instances which refer to sockets. } {$EXTERNALSYM TSocket} TSocket = u_int;
早い話、Integerである。単なる整数値。 多分Windowsプログラミングで使うところのハンドルにあたるものだと思う。
ソケット作成に失敗した場合は、
{$EXTERNALSYM INVALID_SOCKET =} INVALID_SOCKET = TSocket(NOT(0));が返ってくる。
逆に、ソケットを廃棄する場合は、
{$EXTERNALSYM closesocket} function closesocket(s: TSocket): Integer; stdcall;
今日のところはこの2つ、作成・廃棄をやってみよう。
ソケットの作成・破棄 | TOP |
こんな感じで。
implementation var Sock: TSocket;
複数のボタンで、1つのソケット変数を操作するために、ユニット変数として ソケットを宣言しておく。
procedure TForm1.Button12Click(Sender: TObject); begin Sock := socket(AF_INET, SOCK_STREAM, IPPROTO_IP); //if Sock = INVALID_SOCKET then //begin // ShowMessage('INVALID_SOCKET'); //end; ShowMessage(SysErrorMessage(WSAGetLastError)); end;
で、Button12Clickが、ソケットの作成。 で、予想通り、WSAStartupを呼び出したあとで、socketを呼び出さなければエラーになる。
WSAStartupより先に、上のコードで走らせると、 「アプリケーションが WSAStartup を呼び出していないか、または WSAStartup が失敗しました。」こんなエラーが表示される。つまり、WSAGetLastErrorが、エラーコードをつかんでくる。
ところが、上記コード中のコメント行を4行とも有効にすると、状況が変わってくる。
の順でメッセージ画表示される。 ここで疑問に思うのは、WSAGetLastErrorを呼び出していないのに、エラーがクリアされているということである。しているのは、変数と定数を比較してメッセージを表示しているだけである。
といいながら今試してわかったことがある。それは、
という点である。こんなことでいいんだろうか。 (※2002/12/05追記:ShowMessageが何らかのAPIを呼び 出しているなら、エラー状態が上書きされている可能性がある。 で、多分そうだろう。ウィンドウをひとつ作ってしかも成功しているわけだから。)
procedure TForm1.Button13Click(Sender: TObject); begin closesocket(Sock); ShowMessage(SysErrorMessage(WSAGetLastError)); end;
それから、Button13Clickが、ソケットの破棄。
こっちは余計に何も考えることなく、作ったソケット変数を渡してやればそれでよい。表示されるエラーは、次の2つだけを確認できた。
1つ目のほうは、socket関数と同じ(つまりいっつもと同じ)エラーだが、2つ目のほうはちょっと違う。こんな感じ。
「ソケット以外のものに対して操作を実行しようとしました。」
ためしにこんなコードで試してみた。
closesocket(1);
なんとコンパイルは通る。だが、実行時には、エラー(「ソケット以外のものに対して操作を実行しようとしました。」)が表示される。
今日はここまで。
getsockname | TOP |
2002/12/05
昨日は、TSocketを作って捨てたので、今回は、TSocketを使う関数を少しずつ見ていこう。とりあえず、getsocknameで。どっかのサイトで拾った説明によると、 「ソケットから自分のマシンのアドレスとポート番号を取得する」ための関数らしい。
{$EXTERNALSYM getsockname} function getsockname(s: TSocket; var name: TSockAddr; var namelen: Integer): Integer; stdcall;
TSocket以外は、すべてvarなので、ここに値がセットされて戻ってくるような気がする。
とりあえず、準備として、TSockAddrについて見る必要がある。
type { Structure used by kernel to store most addresses. } {$EXTERNALSYM PSOCKADDR} PSOCKADDR = ^TSockAddr; {$EXTERNALSYM TSockAddr} TSockAddr = sockaddr_in;
これによると、TSockAddrは、sockaddr_inだとわかる。 じゃあ、sockaddr_inは?というわけで、これが本体らしい。
type PSockAddrIn = ^TSockAddrIn; {$EXTERNALSYM sockaddr_in} sockaddr_in = record case Integer of 0: (sin_family: u_short; sin_port: u_short; sin_addr: TInAddr; sin_zero: array[0..7] of Char); 1: (sa_family: u_short; sa_data: array[0..13] of Char) end; TSockAddrIn = sockaddr_in;
「こける」には、0のほうを見ればよいとある。大きさぐらい見ておくと、 sin_portがu_shortなので、1バイト。sin_addrがTInAddrで4バイト。 sin_zeroがarray[0..7] of Charで8バイト。合計13バイト。 それから、sa_dataが、0..13の14バイト。あれ?一緒になるのかと思ったが。
というわけで、とりあえず、この関数(getsockname)が、ソケットだけを 指定すれば、残りはセットして戻してくるということにして、こんな感じで使ってみる。
procedure TForm1.Button14Click(Sender: TObject); var name: TSockAddr; namelen: integer; begin getsockname(Sock, name, namelen); ShowMessage(SysErrorMessage(WSAGetLastError)); end;
ん?「無効な引数が提供されました。」ときた。
どれが無効かわからん。 とりあえず、namelenに、SizeOf(TSockAddr)を渡すように変更。 大きさは16らしい。だめ。 TSockAddrをそれなりに埋めて渡すように変更。だめ。 結局こんな感じになったが、まったくおんなじエラーが出つづける。 もちろん、オープン処理・ソケット作成はやってある。 どこが何なんだろう。
var name: TSockAddr; namelen: integer; retvalue: integer; begin FillChar(name, SizeOf(TSockAddr), #0); namelen := SizeOf(TSockAddr); name.sin_family := AF_INET; name.sin_port := htons(IPPORT_FTP); name.sin_addr.S_addr := inet_addr('127.0.0.1'); retvalue := getsockname(Sock, name, namelen); ShowMessage(SysErrorMessage(WSAGetLastError)); ShowMessage(IntToStr(retvalue)); end;
時間が無いのでここまで。
(未完)
EOF | TOP |