C ベースの HTTP クライアント
C の API には、libcurl の機能に関する API が 2 つ用意されています。easy インターフェースは同期型の単純な API です (つまり、あるリクエストで libcurl を呼び出すと、リクエストは libcurl の処理が完了するまで、あるいはエラーが発生するまで待ってから処理を続けます)。マルチ・インターフェースは libcurl を詳細に制御できるため、アプリケーションは複数の転送を同時に実行することができ、またいつどこで libcurl がデータを転送すればよいかを制御することができます。
この例では easy インターフェースを使います。この API でも (コールバックを使うことで) データの転送プロセスを多少制御することができますが、easy という名前のとおり容易に行うことができます。リスト 3 は C 言語による HTTP の例です。
リスト 3. libcurl の easy インターフェースを使った C による HTTP クライアント
#include <stdio.h>
#include <string.h>
#include <curl/curl.h>
#define MAX_BUF 65536
char wr_buf[MAX_BUF+1];
int wr_index;
/*
* Write data callback function (called within the context of
* curl_easy_perform.
*/
size_t write_data( void *buffer, size_t size, size_t nmemb, void *userp )
{
int segsize = size * nmemb;
/* Check to see if this data exceeds the size of our buffer. If so,
* set the user-defined context value and return 0 to indicate a
* problem to curl.
*/
if ( wr_index + segsize > MAX_BUF ) {
*(int *)userp = 1;
return 0;
}
/* Copy the data from the curl buffer into our buffer */
memcpy( (void *)&wr_buf[wr_index], buffer, (size_t)segsize );
/* Update the write index */
wr_index += segsize;
/* Null terminate the buffer */
wr_buf[wr_index] = 0;
/* Return the number of bytes received, indicating to curl that all is okay */
return segsize;
}
/*
* Simple curl application to read the index.html file from a Web site.
*/
int main( void )
{
CURL *curl;
CURLcode ret;
int wr_error;
wr_error = 0;
wr_index = 0;
/* First step, init curl */
curl = curl_easy_init();
if (!curl) {
printf("couldn't init curl\n");
return 0;
}
/* Tell curl the URL of the file we're going to retrieve */
curl_easy_setopt( curl, CURLOPT_URL, "www.exampledomain.com" );
/* Tell curl that we'll receive data to the function write_data, and
* also provide it with a context pointer for our error return.
*/
curl_easy_setopt( curl, CURLOPT_WRITEDATA, (void *)&wr_error );
curl_easy_setopt( curl, CURLOPT_WRITEFUNCTION, write_data );
/* Allow curl to perform the action */
ret = curl_easy_perform( curl );
printf( "ret = %d (write_error = %d)\n", ret, wr_error );
/* Emit the page if curl indicates that no errors occurred */
if ( ret == 0 ) printf( "%s\n", wr_buf );
curl_easy_cleanup( curl );
return 0;
}
|
リストでは、まず先頭に、cURL のルート・ファイルなど、必要な include ファイルがあります。次に、転送のための変数をいくつか定義しています。最初の wr_buf は受信されるデータが書き込まれるバッファーを表します。wr_index はバッファーに対する現在の書き込みインデックスを表します。
下に下がると、main 関数では easy API を使ってセットアップを行っています。cURL の呼び出しはすべて、個別のリクエストに対する状態を管理するハンドルによって行われます。これは CURL ポインターの参照として定義されています。またこの例では、CURLcode という特別なリターン・コードを作成しています。どの libcurl 関数を使用するよりも前に、curl_easy_init を呼び出して CURL ハンドルを取得する必要があります。次に、いくつかの curl_easy_setopt 呼び出しがあることに注目してください。これらを呼び出すことによって、個別の操作に対するハンドルを構成します。これらを呼び出す場合には、ハンドル、コマンド、そしてオプションを指定します。この例ではまず、CURLOPT_URL を使用して取得対象の URL を指定しています。次に、CURL_WRITEDATA を使用してコンテキスト変数 (この場合には内部書き込みエラー変数) を指定しています。最後に、CURLOPT_WRITEFUNCTION を使用して、データが受信された時に呼び出す必要がある関数を指定しています。この API はこの関数を 1 回呼び出すことになるか、あるいはこの関数の実行を開始した後に読み取ったデータを引数として何度も呼び出すことになります。
転送を開始するためには curl_easy_perform を呼び出します。この関数の役割は、この関数が呼び出される前の構成に従って転送を実行することです。この関数を呼び出すと、転送が完了するかエラーが発生するまでこの関数からは戻りません。main で最後に行う処理は、リターン・ステータスを出力し、読み取ったページを出力し、そして最後に (ハンドルを使い終わったら) curl_easy_cleanup を使ってクリーンアップを行います。
今度は write_data 関数を見てみましょう。この関数は、特定の操作に対してデータが受信されると呼び出されるコールバック関数です。Web サイトからデータを読み取っている間に、write_data によってデータが書き込まれることに注意してください。このコールバック関数は引数として、(受信されたデータを含む) バッファー、メンバーの数とサイズ (この積はバッファーの中のデータの合計です)、そしてコンテキスト・ポインターを取ります。最初のタスクは、バッファー (wr_buf) にデータを書き込むための十分なスペースがあるかどうかを確認することです。十分なスペースがない場合には、コンテキスト・ポインターを設定してゼロを返し、問題があったことを知らせます。それ以外の場合には、cURL のバッファーからデータ書き込み用のバッファーにデータをコピーし、インデックスをインクリメントして次にデータを書き込む場所に設定します。またこの例では、後で printf を使って出力できるように文字列の終端の処理も行っています。最後に、操作対象となったバイト数を libcurl に返しています。バイト数を返すことによって、データが取り込まれたことを libcurl に伝え、libcurl はそのデータを破棄します。たったこれだけです。Web サイトからファイルを読み取ってメモリーに入れる方法としては比較的単純です。
上に戻る
Python ベースの HTTP クライアント
このセクションでは、C ベースの HTTP クライアントに似た例を Python で作成します。Python はオブジェクト指向の便利なスクリプト言語であり、本番ソフトウェアのプロトタイピングや構築に最適です。この例では、ある程度 Python を理解していることを前提にしますが、ほとんど Python の知識を使わないので、それほど深く理解している必要はありません。
Python で pycurl を使った簡単な HTTP クライアントをリスト 4 に示します。
リスト 4. Python で libcurl の pycurl インターフェースを使った簡単な HTTP クライアント
import sys
import pycurl
wr_buf = ''
def write_data( buf ):
global wr_buf
wr_buf += buf
def main():
c = pycurl.Curl()
c.setopt( pycurl.URL, 'http://www.exampledomain.com' )
c.setopt( pycurl.WRITEFUNCTION, write_data )
c.perform()
c.close()
main()
sys.stdout.write(wr_buf)
|
この例は C のバージョンよりもはるかに単純です。まず、必要なモジュールをインポートします (標準的なシステム・モジュールの sys と pycurl モジュール)。次に、書き込みバッファー (wr_buf) を定義します。C プログラムの場合と同様、write_data 関数を定義しています。この関数が引数を 1 つ取ることに注意してください (HTTP サーバーから読み取られたデータ・バッファー)。ここでは単純に、このバッファーをグローバルな書き込みバッファーに連結しています。main 関数では最初に Curl ハンドルを作成し、次に setopt メソッドを使ってトランザクション用の URL と WRITEFUNCTIONを定義しています。そして perform メソッドを呼び出して転送を開始し、最後にハンドルを閉じています。このリストの最後では、main 関数を呼び出し、書き込みバッファーを stdout に出力しています。この場合はエラー・コンテキストのポインターが必要ないことに注意してください。これは、Python のストリング連結を使っており、静的に大きさが決められたストリングを使わないためです。
上に戻る