NetFD: C言語用ネットワーク I/O ライブラリ

更新履歴

[2007/10/02 (Tue)]
netfd_udp_client() API の変更した netfd 1.2-RELEASE を公開。

[2007/09/03 (Mon)]
netfd 1.1.3-RELEASE を公開。

概要

NetFD は、ネットワークソフトウェアを簡単に実装するためのライブラリです。 ライブラリの元となったコードは、 wyvern:ミニウェブサーバに同梱のライブラリ Wyvern Thread Library (WTL) です。 この WTL からマルチスレッド機能を削除し、サーバ/クライアント向けに API を改良したライブラリとなっています。 Raw IP や BPF 用の API も実装してあります。 sxml:簡易 XML 解析ライブラリの XML-RPC 用のサーバ・コードも本ライブラリのソースコードを元に実装されています。

ダウンロード

NetFD 1.2-RELEASE(2007/10/02)

パッケージ名 サイズ MD5値
netfd-1.2.tar.gz 98,947 a5a166997a3925219c99055c0b863633
netfd-1.2.tar.bz2 85,170 3052c2949086e7850be37556219f08fe

ライブラリの使い方

ライブラリの使い方として、 ここでは TCP 版の daytime サーバとクライアントを例に説明します。 daytime サーバは、Unix 系 OS であればポート番号 13 でサービスを提供しています。 しかし最近の OS では、標準状態ではポートは閉じられています。

daytime サーバの実装

NetFD ライブラリを利用する場合は、必ず netfd_init() を呼び出さなければなりません。 netfd_init() は、引数にオープンする最大のファイル記述子の数を指定します。 0 を指定した場合は、デフォルトの値を利用します。 戻り値は、成功の場合には 0 が、失敗の場合は -1 が返されます。


int main(int argc, char * argv[])
{
  if (netfd_init(0) == 0) {
    ...
  }

  return 0;
}

TCP サーバを実装する場合は、netfd_tcp_server() を使います。 引数には、IPアドレス、ポート番号と待ち行列の値を指定します。 戻り値には、新しい NetFD ポインタが返されます。 失敗した場合は、NULL が返されます。


int main(int argc, char * argv[])
{
  if (netfd_init(0) == 0) {
    NetFD nsd;

    nsd = netfd_tcp_server(DEF_ADDR, DEF_PORT, DEF_BACKLOG);
    ...
  }

  return 0;
}

netfd_read_event_add() は、 NetFD ポインタで指定された変数に読み込みのイベントを監視するように設定します。 netfd_dispatch() は、実際の処理を行う関数を登録します。 最初の引数はコールバック関数、ここでは daytime() を指定します。

二番目の引数は、クライアントから接続があった場合に、 データを読み込まずに即座に応答を返す場合は true を指定します。 それ以外の場合は、false を指定します。

最後の引数は、タイムアウトを指定します。 0 を指定した場合は、ポーリングモードになります。 負の値を指定した場合は、タイムアウトを無効にします。 それ以外は、指定した値をミリ秒と解釈してタイムアウトを指定します。


int main(int argc, char * argv[])
{
  if (netfd_init(0) == 0) {
    NetFD nsd;

    nsd = netfd_tcp_server(DEF_ADDR, DEF_PORT, DEF_BACKLOG);
    if (nsd != NULL) {
      netfd_read_event_add(nsd);
      netfd_dispatch(daytime, true, -1);
      netfd_close(nsd);
    }
  }

  return 0;
}

daytime() は、クライアントからの要求を処理する関数です。 ここでは、単純に日付と時刻を返すだけです。 クライアントからの接続があった場合に呼び出されます。 一般的なサーバと違いクライアントからのデータの読み込みは行わず、 一方的にデータを返します。

データの書き込みには、netfd_write() を使います。 書式はタイムアウトを指定できる以外は、write(2) とほぼ同じです。


static void daytime(NetFD nfd)
{
  time_t ticks = time(NULL);
  char   buf[256];

  memset(buf, 0, sizeof(buf));
  snprintf(buf, sizeof(buf), "%.24s\r\n", ctime(&ticks));
  netfd_write(nfd, buf, strlen(buf), NETFD_NO_TIMEOUT);
  netfd_close(nfd);
}

TCP版 daytime サーバプログラム daytime_s.c は、 以下のとおりです。


#include <stdio.h>
#include <string.h>
#include <time.h>
#include <netfd.h>

#define DEF_ADDR    "192.168.1.23"
#define DEF_PORT    "31415"
#define DEF_BACKLOG (2)

static void daytime(NetFD nfd)
{
  time_t ticks = time(NULL);
  char   buf[256];

  memset(buf, 0, sizeof(buf));
  snprintf(buf, sizeof(buf), "%.24s\r\n", ctime(&ticks));
  netfd_write(nfd, buf, strlen(buf), NETFD_NO_TIMEOUT);
  netfd_close(nfd);
}

int main(int argc, char * argv[])
{
  if (netfd_init(0) == 0) {
    NetFD nsd;

    nsd = netfd_tcp_server(DEF_ADDR, DEF_PORT, DEF_BACKLOG);
    if (nsd != NULL) {
      netfd_read_event_add(nsd);
      netfd_dispatch(daytime, true, -1);
      netfd_close(nsd);
    }
  }

  return 0;
}

次のコマンドを実行してコンパイルします。

  % gcc -I/usr/local/include -L/usr/local/lib daytime_s.c -o daytime_s -lnetfd

daytime クライアントの実装

TCP クライアントを実装する場合は、 netfd_tcp_client() を使います。 引数には、サーバの IPアドレス、ポート番号とタイムアウトです。 戻り値には、新しい NetFD ポインタが返されます。 失敗した場合は、NULL が返されます。


int main(int argc, char * argv[])
{
  if (netfd_init(0) == 0) {
    NetFD nfd;

    nfd = netfd_tcp_client(DEF_ADDR, DEF_PORT, DEF_TIMEOUT);
    ...
  }

  return 0;
}

TCP版 daytime クライアントプログラム daytime_c.c は、 以下のようなサーバから送られて来たデータを表示する単純なプログラムです。

なお、データの読み込みには、netfd_read() を使います。 書式はタイムアウトを指定できる以外は、read(2) とほぼ同じです。


#include <stdio.h>
#include <string.h>
#include <netfd.h>

#define DEF_ADDR    "192.168.1.23"
#define DEF_PORT    "31415"
#define DEF_TIMEOUT (5000) /* milliseconds */

int main(int argc, char * argv[])
{
  if (netfd_init(0) == 0) {
    NetFD nfd;

    nfd = netfd_tcp_client(DEF_ADDR, DEF_PORT, DEF_TIMEOUT);
    if (nfd != NULL) {
      ssize_t n;
      char    buf[256];

      memset(buf, 0, sizeof(buf));
      while ((n = netfd_read(nfd, buf, sizeof(buf), NETFD_NO_TIMEOUT)) > 0) {
        fprintf(stdout, "%s", buf);
        memset(buf, 0, sizeof(buf));
      }
      netfd_close(nfd);
    }
  }

  return 0;
}

次のコマンドを実行してコンパイルします。

  % gcc -I/usr/local/include -L/usr/local/lib daytime_c.c -o daytime_c -lnetfd

おまけ:超ミニミニウェブサーバ

CGI などを使用せず静的なコンテンツのみの配信を行いたい場合、 Wyvern:ミニウェブサーバのおまけで説明したウェブサーバよりも、 より軽量で、より高速に動作するウェブサーバがあります。 これは、シングルスレッドで動作するため、 余計なコンテキストの切り替えが発生しないからです。 Wyvern のおまけのミニミニサーバでは、 コンテキストの切り替えに数ミリ秒かかります。

元となったソースコードは、Wyvern のおまけのミニミニサーバです。 そのため、オプションや実装方針は全く同じです。 同様に、ライブラリの使用例として実装したプログラムなので、 ソースコード中に examples/httpd.c というファイル名で入っています。 NetFD をコンパイルした後であれば、次の手順でコンパイルできます。

  % cd examples
  % make httpd

起動も簡単で、オプションはすべてコマンドラインの引数で指定します。 ただし、デーモン化しないので手動でバックグラウンドのプロセスにします。

  % ./httpd -a 192.168.1.23 -p 80 -d /usr/local/www/htdocs
    -l /var/log/httpd.log -u www &
Google