WinSockをちょっと試してみたところで、今度はサーバーに接続してとりあえず何か通信してみましょう。
ちょっと長いのですが、以下のプログラムは、googleのサーバーに接続してインデックスページを取得してくるだけのプログラムです。
program connect;
{$APPTYPE CONSOLE}
uses
Windows, SysUtils, WinSock;
var
WSAData: TWSAData;
phe: PHostEnt;
s: TSocket;
sockadd: sockaddr_in;
buf: string;
cnt: Integer;
begin
// WinSock 初期化
WSAStartup($0101, WSAData);
//---------------------------
// ソケットを作成 ... (1)
s := socket(PF_INET, SOCK_STREAM, 0);
if(s = INVALID_SOCKET)then
raise Exception.Create('ソケットを作成できませんでした。');
//---------------------------
// ホスト情報を得る
phe := gethostbyname('www.google.com');
if phe = nil then raise Exception.Create('ホストがみつかりません。');
// 接続先アドレスを設定 ... (2)
ZeroMemory(@sockadd, Sizeof(sockadd));
sockadd.sin_family := AF_INET;
sockadd.sin_port := htons(80);
sockadd.sin_addr := PInAddr(phe.h_addr_list^)^;
//---------------------------
// 接続
if WinSock.connect(s, sockadd, sizeof(sockadd)) <> 0 then
raise Exception.Create('接続できませんでした。');
SetLength(buf, 1024 * 8); // 8Kのバッファ
//---------------------------
// 送信 ...(3)
StrCopy(@buf[1], 'GET ./ HTTP/1.0'#13#10#13#10);
send(s, PChar(buf)^, StrLen(@buf[1]), 0);
//---------------------------
// 受信 ...(4)
while True do
begin
ZeroMemory(PChar(buf), Length(buf)); // メモリの初期化
cnt := WinSock.recv(s, buf[1], Length(buf)-1, 0);
if cnt = 0 then Break;
if cnt = SOCKET_ERROR then
begin
cnt := WSAGetLastError;
writeln('受信エラー=', cnt); Break;
end;
Writeln(string(PChar(buf))); // 受信したデータを画面に表示
if Length(buf) > cnt then Break; // データを読みきった
end;
//---------------------------
// 切断...(5)
if (shutdown(s, SD_BOTH) <> 0) then writeln('シャットダウンに失敗');
closesocket(s);
WSACleanup;
readln;
end.
前回もやったように、とりあえず、WSAStartupでWinSockを初期化します。それから、サーバーに接続するためには、まず、ソケットを作る必要があります。
そのため、プログラム中の(1)では、socketでソケットを作成します。そして、次にサーバーへ接続するのですが、接続のための connect 関数の引数の第二引数でsockaddr_inが必要になります。これは、(2)で設定しているのですが、前回やった、gethostbynameでIPアドレスを取得したもの、ポート番号、アドレスの種類を設定します。
接続ができたらあとは、待ちに待った送信です。送信は(3)のsend です。ここでは、GETコマンドをサーバーに送信します。この辺りは、HTTPプロトコルの話になるので、『"HTTPコマンド" GET』などのキーワードで検索するといろいろ出てきます。
受信処理が(4)なんですが、受信したデータが、バッファに入りきらないことがあるので、受信サイズが0になるまで繰り返し、受信を行います。
最後(5)では、接続を切断して終了です。
たかだか、サーバーに接続してインデックスページを得るだけなのに、ものすごくたくさんプログラムを記述しなくてはならず、骨が折れますね。
TCP/IPクライアントが簡単に作れるユニットを作ってしまいましょう。
では、全てをまとめあげた成果を見ていただきましょう。
program clientTest;
{$APPTYPE CONSOLE}
uses
WSockUtils;
var
client: TTcpClient;
s: string;
begin
client := TTcpClient.Create; // クラスの生成
try
client.connect('www.google.com', 80); // 接続
client.send('GET ./ HTTP/1.0'#13#10#13#10); // コマンドの送信
writeln(client.recvAll); // データの受信
finally
client.Free; // クラスの破棄
end;
readln; // 待機
end.
肝心のまとめたユニットは以下よりダウンロードしてください。内容は上のプログラムをただユニットに移し変えただけのしろものなので、敢えてプログラムを示すことはしません。
→googleのインデックスページ取得(ユニット版)