Windows 再インストール時の手順

2009 年 4 月 6 日

データの移行漏れなどがないよう、自分が作業するときの手順をメモっておきます。

前準備

  1. 単語辞書を書き出す
  2. Firefoxのデータのバックアップ → Firefoxの設定情報をバックアップする
  3. iTunesのデータのバックアップと認証の解除

OSインストールとドライバインストール

以下の順番でインストールをすると不具合が少ない。

  1. OSインストール
  2. WindowsUpdate
  3. チップセットドライバ(INFパッチ)を入れる
  4. DirectX入れる
  5. WindowsUpdate(DirectX)
  6. グラフィックボードのドライバ入れる
  7. その他ドライバ入れる

アプリケーションのインストールと各種設定

  1. IEのテンポラリ領域をCドライブ以外に設定
  2. Cドライブにスワップしないよう設定
  3. データのバックアップのタスク設定
  4. ウィルス対策のソフトを忘れずに入れる
  5. その他いつものアプリ入れる
  6. WindowsUpdate
  7. デブラグ

FirefoxのAddon

いつものAddon

  1. All-in-One Gestures
  2. Screen grab
  3. tab Mix Plus
  4. IE Tab

ADT(Android Development Tools) のインストール

2009 年 4 月 2 日

Android Development Tools for Eclipse とは

ADTを導入することで、EclipseでAndroidのプロジェクトが作成可能になります。Andoroidの開発には必須のツールです。

Eclipse のダウンロード・インストール

まずは、Eclipse がないと始まりません。

  1. EclipseをEclipseのサイトのDownloadsからダウンロードします。
    Eclipse ダウンロード

    Eclipse ダウンロード

  2. Eclipse IDE for Java Developers を選択
  3. ダウンロードしたファイルを解凍し、「C:\Program Files\」等に置く

ADTのダウンロードとインストール

  1. ADTはAndoroidのDeveloperサイトからダウンロードできます。
  2. ダウンロードしたADT-X.X.X.zip ファイルは解凍する必要はありません。
  3. Eclipseを起動し、Eclipseの「Help」メニューから「Software Updates」を選択します。
    HelpメニューからSoftwareUpdatesを選択

    HelpメニューからSoftwareUpdatesを選択

  4. 「Add Sites」を選択し、「Archive」から先ほどダウンロードしたADTのzipファイルを指定します。
    Add SitesからArchiveを選択

    Add SitesからArchiveを選択

  5. zipファイルの中身が表示されるので、「Developer Tools」を選択し、「Install」を実行します。
    Developer Toolsを選択

    Developer Toolsを選択

  6. ライセンスの確認画面が出るので、Acceptを選択し、インストールを進めます。
    ADTのライセンスの確認

    ADTのライセンスの確認

  7. インストールが終わったら、Eclipseを再起動して完了です。

Android SDKの設定

  1. 「Window」メニューから「Preference」を選択します
    adk-preference
  2. 「Android」を選択し、「SDK Location」にAndroid SDKの場所を設定します。
    android_dev_tool_path

設定の確認

  1. 新規プロジェクト画面でAndroid プロジェクトが作成可能になっていることを確認します。
    Eclipse Android Project

    Eclipse Android Project

参考文献

Google Androidアプリケーション開発入門 画面作成からデバイス制御まで――基本機能の全容
Google Androidアプリケーション開発入門
Google Androidプログラミング入門
Google Androidプログラミング入門

全国郵便番号XMLデータ

2009 年 3 月 30 日

日本郵政の郵便番号データをXML形式に変換したものを用意する機会があったので、公開してみます。
文字コードはUTF-8です。

attachment filejp_zipcode (1.8MB)

フォーマットは以下のような形式になっています。

<?xml version="1.0"?>
<JapanAreaData>
  <Prefecture>
    <PrefectureKana>ホッカイドウ</PrefectureKana>
    <PrefectureName>北海道</PrefectureName>
    <City>
      <CityName>札幌市中央区</CityName>
      <CityNameKana>サッポロシチュウオウク</CityNameKana>
      <Area>
        <AreaKana>アサヒガオカ</AreaKana>
        <AreaName>旭ケ丘</AreaName>
        <ZipCode>0640941</ZipCode>
      </Area>
      <Area>
        <AreaKana>オオドオリヒガシ</AreaKana>
        <AreaName>大通東</AreaName>
        <ZipCode>0600041</ZipCode>
      </Area>
            :
    </City>
    <City>
      <CityName>札幌市北区</CityName>
      <CityNameKana>サッポロシキタク</CityNameKana>
              :
    </City>
  </Prefecture>
  <Prefecture>
    <PrefectureKana>アオモリケン</PrefectureKana>
    <PrefectureName>青森県</PrefectureName>
          :
  </Prefecture>
</JapanAreaData>

元データは日本郵政のサイトにおいてある、CSVファイルです。Perlで書いた変換スクリプトでXMLに変換しました。

郵便番号CSVデータをXMLに変換するスクリプト

#!/usr/bin/perl

use strict;
use XML::Simple;

my $hash;
my %tmp_hash;
my $i;

$hash->{'Prefecture'} = [];

my $current_pref;
my $current_city;
my $pref_prefix = -1;
my $city_prefix = -1;

while (<>) {
        chomp;
        s/"//g;
        my ($idnum, $zip5, $zip7, $pref_kana, $city_kana, $area_kana, $pref, $city, $area) = split(/,/);

        if ($area eq '以下に掲載がない場合') {
                next;
        }

        if ($current_pref ne $pref) {
                $pref_prefix++;
                $city_prefix = -1;

                $current_pref = $pref;
                $current_city = "";

                push(@{$hash->{'Prefecture'}}, { 'PrefectureName' => $pref, 'PrefectureKana' => $pref_kana, 'City' => [] });
        }

        if ($current_city ne $city) {
                $city_prefix++;
                $current_city = $city;

                push(@{$hash->{'Prefecture'}[$pref_prefix]->{'City'}}, { 'CityName' => $city, 'CityNameKana' => $city_kana, 'Area' => [] });
        }
        push(@{$hash->{'Prefecture'}[$pref_prefix]->{'City'}[$city_prefix]->{'Area'}}, { 'ZipCode' => $zip7, 'AreaName' => $area, 'AreaKana' => $area_kana });
}

print XMLout($hash,  NoAttr => 1, RootName => 'JapanAreaData');

プロファイラ gprof の使い方

2009 年 3 月 26 日

gprof GNU Profiler とは

プロファイラあるプログラム中で使用される関数毎に、その実行回数や実行時間を分析して表示するツールです。プログラムが思ったようなパフォーマンスが出ない場合、ボトルネックになっている場所を特定するために利用します。

実行例

  %   cumulative   self              self     total
 time   seconds   seconds    calls  ms/call  ms/call  name
  0.0       0.00     0.00        3     0.00     0.00  read [1] //read()が3回
  0.0       0.00     0.00        2     0.00     0.00  write [2] //write()が2回 呼ばれている
  0.0       0.00     0.00        1     0.00     0.00  ___sysctl [138]
  0.0       0.00     0.00        1     0.00     0.00  _close [139]
  0.0       0.00     0.00        1     0.00     0.00  _mcleanup (140)
  0.0       0.00     0.00        1     0.00     0.00  _profil [141]
  0.0       0.00     0.00        1     0.00     0.00  moncontrol [3]
  0.0       0.00     0.00        1     0.00     0.00  open [4]
  0.0       0.00     0.00        1     0.00     0.00  sysctl [5]

それぞれ、

  • 実行時間(全体に対する %)
  • 実行時間の累積(秒)
  • 実行時間(秒)
  • 関数の実行された回数
  • 1回の関数実行にかかる時間(ミリ秒)
  • 1回の関数実行にかかる時間の合計(ミリ秒)
  • 関数名

を表しています。

使い方

gprofを使うには「-pg」オプションをつけてコンパイルする必要があります。

$ gcc -pg -o test.o test.c

あとは、実行ファイルを普通に実行します。このとき、gprofのデータファイルが同じディレクトリに生成されます。

$ ./test.o

「gprof 実行ファイル データファイル」とすると、解析結果が出力されます。

$ gprof test.o test.o.gmon

参考文献

Debug Hacks -デバッグを極めるテクニック&ツール
Debug Hacks
GNU Make 第3版
GNU Make 第3版

参考URL

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