カテゴリ
リンク

当サイトは、玄箱PRO (KURO-BOX/Pro)を中心とした組み込み、Linuxと電子工作を扱っています。
会社案内

情報セキュリティおよび個人情報の取り扱いについて


コメントとトラックバックは、spamを予防するために、編集担当が公開の作業をするまで非公開になっています。コメントはそれぞれ投稿した人のものです。

■ソケット・プログラミング
 LCDd や mpd と接続するクライアントのプログラムを C言語で書く場合にはソケット・プログラミング*1)をします。決まり事がいくつかありますが、それさえ守れば難しくはありません。ここでは、簡単な LCDd クライアント tcp-ex.c で、手順を見ていきます。tcp-ex.c は、LCDd の液晶上に test という文字を書き 5秒後に終了するプログラムです。

■コネクションを張る
 サーバにクライアントから接続することをコネクションを張るといいます。サーバは、ホスト名とポート番号で特定されます。玄箱PRO上のプログラム同士の場合は、ホスト名は localhost (そのマシン自身を表す特別な名前です) になります。LCDd はデフォルトでは、ポート番号 13666 番で接続を待っています。

 tcp-ex.c では、サーバへの接続を connect_to_lcdd()関数で行っています。接続先の LCDd は、引数のホスト名 host (DNS または /etc/hosts で正しく引くことができるものとする), ポート番号 port で指定します。

 手順としては、まず socket() 関数を呼び、通信用のソケットと呼ばれるものを用意します(1)。ソケット・プログラミングの名前は、ここからつけられています。引数の PF_INET はインターネット・プロトコル, SOCK_STREAM は TCP 通信を表します。三つ目の引数は、ここでは0でかまいません。

 つぎに、ホスト名やポート番号などを sockaddr_in 構造体にセットしていきます。(2)ではインターネット・プロトコルであること、(3)でポート番号を、(4)でホスト名から変換したホスト情報をセットします。(5)で型の変換をします。

最後に、connect()関数を呼びます(6)。無事、接続できれば、通信を行います。

int
connect_to_lcdd(char *host, int port)
{
  int sock;
  struct sockaddr_in s;
  struct hostent *hinfo;

  sock = socket(PF_INET, SOCK_STREAM, 0);       ← (1)
  if (sock<0) {
    fprintf(stderr, "Could not create socket\n");
    exit(1);
  }
 
  s.sin_family = AF_INET;               ← (2)
  s.sin_port = htons(port);              ← (3)

  if ((hinfo = gethostbyname(host)) == NULL) {     ← (4)
    fprintf(stderr, "Unknown host %s.\n", host);
    exit(1);
  }

  s.sin_addr = *(struct in_addr *)hinfo->h_addr;    ← (5)

  if (connect(sock, (struct sockaddr *)&s, sizeof(s)) < 0) { ← (6)
    fprintf(stderr, "Could not connect to %s port %d.\n", host, port);
    exit(1);
  }
  return sock;
}

■通信する
 通信は、read(), write()関数(または send(), recv()関数)でファイルに書き込むように行います。init_connection では、write関数で、LCDd に hello を送っています。

  write(sock, "hello\n", 6);
  if (mygets(sock, buf, sizeof(buf))>0) {
    printf("%s", buf);
  }

 注意が必要なのは、read() で受信するときです。プログラマが期待する区切りで、データが送られてくるとは限らないからです。mygets()関数内では、次のように、改行文字を受け取るまで、1バイトずつ read() 関数を繰り返し呼び出しています。本格的なプログラムでは、もう少し効率のよい方法をとります。

  for (i=0; i<(len-1); i ++) {
    if (read(sock, rbuf, 1) == 1) {
      if (*rbuf == '\n')
    break;
      rbuf ++;
      continue;
    }
    usleep(200*1000);
  }

 init_connection() を呼び出して、LCDd との通信の初期化を行った後は、コマンドを while() ループ内で write()関数で送り、その都度 success が LCDd から返されるのを wait_success() 関数(内部で mygets() 関数を呼び出している)で確かめています。

■接続を切る
 接続を切るには、shutdown()関数を呼び出してから、close()関数を呼び出します。

  shutdown(sock, SHUT_RDWR);
  close(sock);


*1) WikiPedia にも、簡単な socket プログラミングの説明が載っています
http://ja.wikipedia.org/wiki/%E3%82%BD%E3%82%B1%E3%83%83%E3%83%88_%28BSD%29

<光永 法明>

 カテゴリ 

 

トラックバック(0)

このブログ記事を参照しているブログ一覧: 簡単ソケット・プログラミング

このブログ記事に対するトラックバックURL: http://www.eleki-jack.com/mt/mt-tb.cgi/784

コメントする

おすすめ書籍
Powered by
Movable Type 4.1