‘C言語’ タグのついている投稿

Makefile中の環境変数を無視する

2009 年 3 月 26 日 木曜日

Makefile中の環境変数を無視する

「-e」オプションでMakefile中で設定されている環境変数を上書きすることができる。

サンプルMakefile

CFLAGS = -O -Wall

a.out: main.c
$(CC) $(CFLAGS) main.c -o $@

make

$ make //普通にmake
cc -O -Wall main.c -o a.out

$ export CFLAGS=” //CFLAGSをなしに
$ touch main.c
$ make -e
cc main.c -o a.out

「-e」オプションの説明
Makeファイル中の変数を上書きする。

-e Specify that environment values override macro assignments within
makefiles for all variables.

参考文献

GNU Make 第3版
GNU Make
CとGNU開発ツールによる組み込みシステムプログラミング 第2版
CとGNU開発ツールによる組み込みシステムプログラミング
GNUソフトウェアプログラミング ―オープンソース開発の原点
GNUソフトウェアプログラミング

[C言語]共有メモリ(shm)を読み書きするサンプルコード

2009 年 3 月 19 日 木曜日

共有メモリとは

共有メモリはその名の通り、複数のプロセスで共有できるメモリである。
プロセス間通信(IPC)に利用される。
親プロセス、子プロセス、無関係なプロセス、どの関係であってもデータの共有が可能。

共有メモリの操作には下記のシステムコールを利用する。

システムコール 説明
shmget() 共有メモリ・セグメント識別子を獲得する
shmat() 自プロセスのデータセグメントにマップ(アタッチとも呼ぶ)する
shmdt() 共有メモリをアンマップ(デタッチとも呼ぶ)する
shmctl() 共有メモリをシステム上から削除する

サンプルプログラム

shm_receiver.c

shmを生成し、1秒置きに、shmの中身を画面に表示する。shmの中身が「end」になると、終了する。

#include <stdio.h>
#include <stdlib.h>
#include <string.h> /* strcpy */
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>

int main(void)
{
    int  id;
    char *adr;

    /* IPC_PRIVATEを指定すると、新規にshmが生成される。*/
    if((id = shmget(IPC_PRIVATE, 512, IPC_CREAT|0666)) == -1){
        perror("shmget");
        exit(-1);
    }

    printf("共有メモリID = %d\n",id);

    /* char形で取得 */
    if(( adr = (char *)shmat(id, NULL, 0)) == (void *)-1){
        perror("shmat");
    } else {
        strcpy(adr,"Initial");
        /* 1秒ごとに出力 */
        while(1){
            printf("%s\n",adr);
            /* 「end」で終了 */
            if (strcmp(adr, "end") == 0) {
                break;
            }
            sleep(1);
        }

        if(shmdt(adr)==-1){
            perror("shmdt");
        }
    }

    /* shmの破壊をする */
    if(shmctl(id, IPC_RMID, 0)==-1){
        perror("shmctl");
        exit(EXIT_FAILURE);
    }

    return 0;
}

shm_writer.c

コマンドラインから与えられた文字列をshmにコピーする。

#include <stdio.h>
#include <stdlib.h>
#include <string.h> /* strcpy */
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>

int main(int argc, char *argv[])
{
    int   id;
    char  *adr;

    if( argc <= 2) {
        fprintf(stderr, "Usage: shm_writer shm_id string\n");
        exit(EXIT_FAILURE);
    }

    id = atoi(argv[1]);

    if(( adr = (char *)shmat(id,0,0)) == (void *)-1) {
        perror("shmat");
    } else {
        strcpy(adr, argv[2]);
        fprintf(stderr, "written.\n");
        if( shmdt(adr) == -1) {
            perror("shmdt");
        }
    }
}

実行例

$ gcc shm_receiver.c -o shm_receiver
$ gcc shm_writer.c -o shm_writer

$ shm_receiver
共有メモリID = 1234 ←IDを覚えておく
Initial

$ shm_writer 1234 hogehoge //shmに「hogehoge」を書き込む。
$ shm_writer 1234 end //shm_receverが終了する。

参考文献

詳解UNIXプログラミング
詳解UNIXプログラミング
例解UNIXプログラミング教室
例解UNIXプログラミング教室
C言語によるUNIXシステムプログラミング入門
C言語によるUNIXシステムプログラミング入門

参考URL

構築環境

FreeBSD 4.10-RELEASE

[C言語]正規表現 サンプルコード

2009 年 3 月 16 日 月曜日

regex.h

C言語で正規表現を使うにはregex.hをincludeします。
具体的に利用する関数はregcomp(), regexec(), regfree()関数の3つです。

regcomp() 関数

int regcomp(regex_t *preg, const char *regex, int cflags)
正規表現のコンパイルを行なう。コンパイル成功時には0を返す。cflags には以下に示す定数一つ以上のビットごとの OR (bitwise-or) を指定する。

REG_EXTENDED
regex に POSIX 拡張正規表現を使用する。もしこのフラグが設定されない場合、POSIX 標準正規表現が使われる。
REG_ICASE
大文字小文字の違いを無視する。
REG_NOSUB
このフラグを設定してコンパイルされたパターンバッファが regexec の引数に指定されると、パラメータ nmatch, pmatch が無視される。
REG_NEWLINE
全ての文字にマッチするオペレータに改行をマッチさせない。

regexec() 関数

int regexec(const regex_t *preg, const char *string, size_t nmatch, regmatch_t pmatch[], int eflags);
正規表現による検索を実行する。eflags には以下に示す定数一つ以上のビットごとの OR (bitwise-or) を指定する。

REG_NOTBOL
行頭にマッチするオペレータは、必ずマッチに失敗する (コンパイル時のフラグ REG_NEWLINE の項目も参照)。このフラグは、複数行にまたがる文字列を regexec() で検索する際に、文字列の先頭を行の先頭として解釈させない場合に用いる。
REG_NOTEOL
行末にマッチするオペレータは、必ずマッチに失敗する。

regfree()関数

void regfree(regex_t *preg)
正規表現パターンバッファを解放する。

正規表現サンプルコード

カンマ区切りの文字列から、数値を取り出す。

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <regex.h>

int main() {
     char str[] = "123, 456, 789";
     regex_t preg;
     size_t nmatch = 5;
     regmatch_t pmatch[nmatch];
     int i, j;

     if (regcomp(&preg, "([[:digit:]]+), ([[:digit:]]+), ([[:digit:]]+)", REG_EXTENDED|REG_NEWLINE) != 0) {
         printf("regex compile failed.\n");
         exit(1);
     }

     printf("String = %s\n", str);

     if (regexec(&preg, str, nmatch, pmatch, 0) != 0) {
         printf("No match.\n");
     } else {
         for (i = 0; i < nmatch; i++) { /* nmatch にマッチした件数が入る */
             printf("Match position = %d, %d , str = ", (int)pmatch[i].rm_so, (int)pmatch[i].rm_eo);
             if (pmatch[i].rm_so >= 0 && pmatch[i].rm_eo >= 0) {
                 for (j = pmatch[i].rm_so ; j < pmatch[i].rm_eo; j++) {
                     putchar(str[j]);
                 }
             }
             printf("\n");
         }
     }

     regfree(&preg);
     return 0;
}

実行結果

$ gcc regex-sample.c
$ ./a.out
String = 123, 456, 789
Match position = 0, 13 , str = 123, 456, 789
Match position = 0, 3 , str = 123
Match position = 5, 8 , str = 456
Match position = 10, 13 , str = 789
Match position = -1, -1 , str =

参考文献

反復学習ソフト付き 正規表現書き方ドリル (WEB+DB PRESS plus)
反復学習ソフト付き
正規表現書き方ドリル

詳説 正規表現 第3版
詳説 正規表現
プログラミング言語C 第2版 ANSI規格準拠
プログラミング言語C

参考URL

[C言語]アラーム サンプルコード

2009 年 3 月 12 日 木曜日

alarm()関数を利用してSIGALRMシグナルを一定時間後に送信することができる。
SIGALRMをキャッチしない場合は、プロセスは終了する。SIGALRM以外のシグナルについては[C言語]シグナルをキャッチする サンプルコードを参照。

alarm(int second);
second秒数後にSIGALRMを送る

サンプルコード

#include <stdio.h>
#include <stdib.h> /* exit */
#include <unistd.h>
#include <signal.h>

void sigcatch(int);

int main() {

    /* Set handler to SIGALRM */
    if (SIG_ERR == signal(SIGALRM, sigcatch)) {
        printf("failed to set signal handler.\n");
    }

    /* 5 seconds after, send signal */
    alarm(5);

    while (1) {
    }

    return 0;
}

void sigcatch(int sig) {
    printf("catch signal %d\n", sig);

    if (sig == SIGALRM) {
        printf("catch SIGALRM and exit.\n");
        exit(1);
    }
}

実行結果

$ gcc alarm-sample.c
$ ./a.out
catch signal 14
catch SIGALRM and exit.

参考文献

入門UNIXシェルプログラミング―シェルの基礎から学ぶUNIXの世界
入門UNIXシェルプログラミング
いますぐ始めるLinuxのC言語
いますぐ始めるLinuxのC言語
これならわかるC 入門の入門

これならわかるC 入門の入門

参考URL

実行環境

Linux Ubuntu 2.6.24, gcc version 4.2.3

[C言語]シグナルをキャッチする サンプルコード

2009 年 3 月 9 日 月曜日

シグナルとは

いわゆる「割り込み」の1つ。動いてるプロセスに対して、他のプロセスから信号を送ることが出来る。

代表的なシグナル

シグナル番号 シグナル名 説明
1 SIGHUP デーモンプロセスに設定の再読み込みをさせるのに良く利用される
2 SIGINT キーボードからの割り込み(Ctrl-C)
9 SIGKILL Kill シグナル。kill -kill [PID]
14 SIGALRM アラーム。一定時間後にSIGALRMを飛ばせる
15 SIGTERM 終了シグナル。kill -term [PID]

signal キャッチ

C言語で、signalをキャッチするには、signal()関数で、シグナルハンドラーを設定する。

signal(シグナルの種類, 受け取った時に実行する関数)

「signalを受け取った時に実行する関数」のことを、一般的に「signalハンドラー」と呼ぶ。
シグナルハンドラーは、1つのintを引数に、戻り値はvoidでなければならない。

typedef void (*sighandler_t)(int);

signal キャッチ サンプル

HUPをうけとると、無限ループしているプログラムを終了させる。
サーバのような、駐屯型のプログラムはこのようにシグナルで終了する仕組になっている。

#include <signal.h>
#include <stdio.h>

void sigcatch(int);

int main() {
    if (SIG_ERR == signal(SIGHUP, sigcatch)) {
        printf("failed to set signal handler.n");
        exit(1);
    }

    while (1) {
        sleep(1);
    }

    return 0;
}

void sigcatch(int sig) {
    printf("catch signal %dn", sig);
    exit(1);
}

シグナルを送る

# ps u
# kill -HUP [プロセス番号]

参考文献

ふつうのLinuxプログラミング Linuxの仕組みから学べるgccプログラミングの王道
ふつうのLinuxプログラミング
プログラミングテクニック―UNIXコマンドのソースコードにみる実践プログラミング手法 (UNIX MAGAZINE COLLECTION)
UNIXコマンドのソースコードにみる実践プログラミング手法
新版 明解C言語 入門編
新版 明解C言語 入門編

[C言語]POSIXスレッドを用いたechoサーバ

2009 年 3 月 5 日 木曜日

サーバの仕組みとスレッド

通常、Webサーバなどは親プロセスがポートをListenし、接続があったら、子プロセスを生成し、その後の(クライアントへのデータ送信等の)処理は、子プロセスに任せるというフローをとる。

そうすることで、親プロセスはクライアントへデータ送信が終わるのを待つ必要がなくなり、どんどん接続を受けることが可能になる。
接続数が多くなると、当然、子プロセスが多くなり、サーバへの過負荷となる。

そこで、子プロセスではなく、スレッドでクライアントの処理を行うと負荷低減につながる((スレッドの生成は子プロセスの生成より軽量))

echoサーバのPOSIXスレッド化

[C言語]Socket間通信 echoサーバを作るで作成したechoサーバにptheadを組み込み、複数クライアントに対して同時処理ができるように改良する。POSIXスレッドについて知りたければ、まずは[C言語]POSIXスレッドプログラミングを参照。

課題

  • 1回の通信が終わっても、Listenし続けるように変更する
  • threadで返答を返すよう変更する

コード

#include <sys/types.h>
#include <sys/socket.h> /* socket(), bind(), listen(), accept(), recv() */
#include <netinet/in.h> /* htons() */
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>     /* exit() */
#include <pthread.h>    /* pthread_create(), pthread_detach() */

#define PORT    8823    /* Listenするポート */
#define MAXDATA 1024    /* 受信バッファサイズ */

void reply(void *);

int main(void)
{
    struct sockaddr_in saddr;
    struct sockaddr_in caddr;

    int listen_fd;
    int conn_fd;

    int len = sizeof(struct sockaddr_in);

    pthread_t worker;

    /* ソケットの生成 */
    if ((listen_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
        perror("socket");
        exit(EXIT_FAILURE);
    }

    /*
     * saddrの中身を0にしておかないと、bind()でエラーが起こることがある
     */
    bzero((char *)&saddr, sizeof(saddr));

    /* ソケットにアドレスとポートを結びつける */
    saddr.sin_family        = PF_INET;
    saddr.sin_addr.s_addr   = INADDR_ANY;
    saddr.sin_port          = htons(PORT);
    if (bind(listen_fd, (struct sockaddr *)&saddr, len) < 0) {
        perror("bind");
        exit(EXIT_FAILURE);
    }

    /* ポートをListenする */
    if (listen(listen_fd, SOMAXCONN) < 0) {
        perror("listen");
        exit(EXIT_FAILURE);
    }
    printf("Start Listening Port : %d...\n", PORT);

    while (1) {
        /* 接続要求を受け付ける */
        if ((conn_fd = accept(listen_fd, (struct sockaddr *)&caddr, &len)) < 0) {
            perror("accept");
            exit(EXIT_FAILURE);
        }

        /* スレッドの生成 */
        if (pthread_create( &worker, NULL, (void *)reply, (void *)conn_fd) != 0) {
            perror("pthread_create");
            exit(EXIT_FAILURE);
        }
        pthread_detach(worker);
    }
    /* Listeningソケットを閉じる */
    close(listen_fd);

}

void reply(void *fd) {
    int conn_fd = (int)fd;

    int rsize;
    char buf[MAXDATA]; /* 受信バッファ */

    /* 送信されたデータの読み出し */
    do {
        rsize = recv(conn_fd, buf, MAXDATA, 0);

        if (rsize == 0) { /* クラアイントが接続を切ったとき */
                break;
        } else if (rsize == -1) {
                perror("recv");
                exit(EXIT_FAILURE);
        } else {
                write(conn_fd, buf, rsize);
        }
    } while (1);

    if ( close(conn_fd) < 0) {
        perror("close");
        exit(EXIT_FAILURE);
    }

    printf("Connection closed.\n");
}

ポイント

  • スレッドにする部分を関数にする
  • 生成したスレッドをdetach状態にする
  • while(1)ループでListenし続ける

参考文献

マスタリングTCP/IP 入門編 第4版
マスタリングTCP/IP 入門編
マスタリングTCP/IP 応用編
マスタリングTCP/IP 応用編
マルチコアCPUのための並列プログラミング―並列処理&マルチスレッド入門
マルチコアCPUのための並列プログラミング

参考URL

Pthreadによる複数クライアントに対するサービスの同時提供
http://www.coins.tsukuba.ac.jp/~yas/coins/syspro-2004/2004-05-10/echo-server-pthread.html
4.2 どうしてソケットがクローズしてくれないのでしょうか?
http://www.kt.rim.or.jp/~ksk/sock-faq/unix-socket-faq-ja-4.html#ss4.2

構築環境

FreeBSD 4.10-RELEASE

[C言語]POSIXスレッドプログラミング サンプル

2009 年 3 月 2 日 月曜日

pthread ライブラリを使った、簡単なスレッドの実装例です。

POSIXスレッド とは

ポジックススレッドと読む。Pthreadと呼ばれることが多い。Pthreadを使うにはpthreadライブラリが必要である。
コンパイル時には「-pthread」オプションを使う((「-lpthread」の場合もある))。

# gcc -pthread source.c

スレッドのメリット/デメリット

スレッドと似た仕組みとして、fork()による子プロセスの生成があるが、スレッドを使うことによる利点がある。
かなりザックリとまとめると、
メリット

デメリット

  • スレッド間の同期処理が面倒
  • 利用するライブラリがスレッドに対応している必要がある

サンプルプログラム

こちらから引用。

POSIXスレッドでは、pthread_create()を使って、新しいスレッドを生成し、pthread_join()を使ってスレッドが終了するのを待つ。
終了を待つ必要がなければ、pthread_detach()を使って切り離せばよい。
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>

void *print_message_function( void *ptr );

main()
{
     pthread_t thread1, thread2;
     char *message1 = "Thread 1";
     char *message2 = "Thread 2";
     int  iret1, iret2;

    /* Create independant threads each of which will execute function */

     iret1 = pthread_create( &thread1, NULL, print_message_function, (void*) message1);
     iret2 = pthread_create( &thread2, NULL, print_message_function, (void*) message2);

     /* Wait till threads are complete before main continues. Unless we  */
     /* wait we run the risk of executing an exit which will terminate   */
     /* the process and all threads before the threads have completed.   */

     pthread_join( thread1, NULL);
     pthread_join( thread2, NULL); 

     printf("Thread 1 returns: %d\n",iret1);
     printf("Thread 2 returns: %d\n",iret2);
     exit(0);
}

void *print_message_function( void *ptr )
{
     char *message;
     message = (char *) ptr;
     printf("%s \n", message);
}

実行結果

$ gcc -pthread sample.c
$ ./a.out
Thread 1
Thread 2
Thread 1 returns: 0
Thread 2 returns: 0

参考文献

Pthreadsプログラミング
Pthreadsプログラミング
Pスレッドプログラミング
Pスレッドプログラミング

参考URL

スレッド・プログラミング
http://www.coins.tsukuba.ac.jp/~yas/coins/dsys-1998/1999-01-19/pthread.html
YoLinux Tutorial: POSIX thread (pthread) libraries
http://www.yolinux.com/TUTORIALS/LinuxTutorialPosixThreads.html
スレッドを用いるメリット
http://mikilab.doshisha.ac.jp/dia/research/person/yoshiki/06.html
Manpage OF PTHREAD_CREATE
http://www.linux.or.jp/JM/html/glibc-linuxthreads/man3/pthread_create.3.html
Manpage OF PTHREAD_JOIN
http://www.linux.or.jp/JM/html/glibc-linuxthreads/man3/pthread_join.3.html
Manpage OF PTHREAD_DETACH
http://www.linux.or.jp/JM/html/glibc-linuxthreads/man3/pthread_detach.3.html

構築環境

FreeBSD 4.10-RELEASE

[C言語]Socket間通信 HTTPクライアントを作る

2009 年 2 月 27 日 金曜日

C言語でのHTTPクライアントの実装例です。
以下の手順でリモートのサーバと通信し、データを取得します。

  1. gethostbyname()によりドメイン名からIPアドレスを引く
  2. socket() によりソケットを開く
  3. connect() によりサーバに接続する
  4. write() でサーバにリクエストを送る
  5. read() でレスポンスを受信する
  6. close() によりソケットを閉じる
#include <stdio.h>
#include <stdlib.h>
#include <string.h> /* bzero */

#include <sys/types.h> /* netinet/in.h */
#include <sys/socket.h> /* AF_INET */
#include <netinet/in.h> /* sockaddr_in */
#include <netdb.h> /* gethostbyname */
#include <sys/uio.h>
#include <sys/param.h>
#include <unistd.h>

#define  DESTSERV "localhost"
#define  DESTPORT 80
#define  MESSAGE  "GET / HTTP/1.0\r\nHOST: localhost\r\n\r\n"
#define  BUF_LEN  1024

int main() {

    struct hostent *hostent;
    struct sockaddr_in server;

    int fd;

    char buf[BUF_LEN]; /* receive buffer */

    hostent = gethostbyname(DESTSERV); /* lookup IP */
    if (hostent == NULL ) {
        fprintf(stderr, "Cannot resolve %s.\n", DESTSERV);
        return 0;
    }

    bzero(&server, sizeof(server)); /* zero clear struct */

    server.sin_family = AF_INET;
    /* server.sin_addr = hostent->h_addr */
    bcopy(hostent->h_addr, &server.sin_addr, hostent->h_length);
    server.sin_port = htons(DESTPORT);

    if ( ( fd = socket(AF_INET, SOCK_STREAM, 0) ) < 0) {
        fprintf(stderr, "Cannot make socket.\n");
        return 0;
    }
    if ( connect(fd, (struct sockaddr *)&server, sizeof(server)) == -1) {
        fprintf(stderr, "Cannot connect.\n");
        return 0;
    }

    write(fd, MESSAGE, strlen(MESSAGE));

    /* Receive data */
    while (read(fd, buf, BUF_LEN) > 0) {
        printf("%s", buf);
    }

    close(fd);
    return 0;
}

サーバ側の実装例については、「C言語でSocket間通信 echoサーバを作る」に記載しています。

参考書籍

猫でもわかるネットワークプログラミング 第2版 (猫でもわかるプログラミングシリーズ)
猫でもわかるネットワークプログラミング
UNIXネットワークプログラミング入門
UNIXネットワークプログラミング入門

[C言語]Socket間通信 echoサーバを作る

2009 年 2 月 25 日 水曜日

ネットワークを通して、データをやりとりするためには、Socketに対して、読み書きをします。
C言語による、Socket間通信は、下記のような手順になります。

  1. socket() によりソケットを開く
  2. bind() により、コネクションを受けつけるIPアドレス・ポート番号と ソケットとを対応づける
  3. listen() によりクライアントからの接続待ち受け状態にする
  4. accept() によりクライアントからの接続を受け付ける
  5. read(), write(), send(), recv() などを用いて通信を行う
  6. close() によりソケットを閉じる

実際に文字列を単純にクライアントに返すだけのプログラム(echoサーバ)を書いて見ます。
ちなみに、本コードでは、1回やりとりが終わると、サーバプロセスも終了します。

#include <stdio.h>
#include <stdlib.h>     /* exit() */
#include <string.h>     /* bzero() */
#include <sys/types.h>
#include <sys/socket.h> /* socket(), bind(), listen(), accept(), recv() */
#include <netinet/in.h> /* htons() */
#include <unistd.h>

#define PORT    8823    /* Listenするポート */
#define MAXDATA 1024    /* 受信バッファサイズ */

int main(void)
{
    struct sockaddr_in saddr; /* サーバ用アドレス格納構造体 */
    struct sockaddr_in caddr; /* クライアント用アドレス格納構造体 */

    int listen_fd;
    int conn_fd;

    int len = sizeof(struct sockaddr_in);

    int rsize;
    char buf[MAXDATA]; /* 受信バッファ */

    /* ソケットの生成 */
    if ((listen_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
        perror("socket");
        exit(EXIT_FAILURE);
    }

    /*
      * saddrの中身を0にしておかないと、bind()でエラーが起こることがある
     */
    bzero((char *)&saddr, sizeof(saddr));

    /* ソケットにアドレスとポートを結びつける */
    saddr.sin_family        = PF_INET;
    saddr.sin_addr.s_addr   = INADDR_ANY;
    saddr.sin_port          = htons(PORT);
    if (bind(listen_fd, (struct sockaddr *)&saddr, len) < 0) {
        perror("bind");
        exit(EXIT_FAILURE);
    }

    /* ポートをListenする */
    if (listen(listen_fd, SOMAXCONN) < 0) {
        perror("listen");
        exit(EXIT_FAILURE);
    }
    printf("Start Listening Port : %d...\n", PORT);

 /* 接続要求を受け付ける */
    if ((conn_fd = accept(listen_fd, (struct sockaddr *)&caddr, &len)) < 0) {
        perror("accept");
        exit(EXIT_FAILURE);
    }

    /* Listeningソケットを閉じる */
    close(listen_fd);

    /* 送信されたデータの読み出し */
    do {
        rsize = recv(conn_fd, buf, MAXDATA, 0);

        if (rsize == 0) { /* クラアイントが接続を切ったとき */
                break;
        } else if (rsize == -1) {
                perror("recv");
                exit(EXIT_FAILURE);
        } else {
                write(conn_fd, buf, rsize);
        }
    } while (1);

    if ( close(conn_fd) < 0) {
        perror("close");
        exit(EXIT_FAILURE);
    }

    printf("Connection closed.\n");
    return 0;
}

実行方法

# gcc echoserver.c -o echoserver
# ./echoserver

別のターミナルで

# telnet localhost 8823
# (適当に文字を打ってみる)
# Ctrl-] //入力終了
telnet> quit //接続切断

参考URL

参考書籍

Linux教科書 LPICレベル1 第4版 (CD-ROM付)
Linux教科書 LPICレベル1
¥ 3,990
UNIXネットワークプログラミング入門
UNIXネットワーク
プログラミング入門
TCP/IPソケットプログラミング C言語編
TCP/IPソケット
プログラミング C言語編
¥ 175より