2009 年 3 月 30 日
日本郵政の郵便番号データをXML形式に変換したものを用意する機会があったので、公開してみます。
文字コードはUTF-8です。
jp_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');
タグ: XML
カテゴリー: 未分類 | コメントはまだありません »
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
参考文献
参考URL
タグ: Binary, gprof, プログラミング
カテゴリー: C言語 | コメントはまだありません »
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.
参考文献
タグ: Binary, C言語, プログラミング
カテゴリー: C言語 | コメントはまだありません »
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が終了する。
参考文献
参考URL
構築環境
FreeBSD 4.10-RELEASE
タグ: C言語, プログラミング
カテゴリー: 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 =
参考文献
参考URL
タグ: C言語, プログラミング
カテゴリー: 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.
参考文献
参考URL
実行環境
Linux Ubuntu 2.6.24, gcc version 4.2.3
タグ: C言語, プログラミング
カテゴリー: 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 [プロセス番号]
参考文献
タグ: C言語, プログラミング
カテゴリー: C言語 | 1 件のコメント »
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し続ける
参考文献
参考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言語, プログラミング
カテゴリー: C言語 | コメントはまだありません »
2009 年 3 月 2 日
pthread ライブラリを使った、簡単なスレッドの実装例です。
POSIXスレッド とは
ポジックススレッドと読む。Pthreadと呼ばれることが多い。Pthreadを使うにはpthreadライブラリが必要である。
コンパイル時には「-pthread」オプションを使う((「-lpthread」の場合もある))。
# gcc -pthread source.c
スレッドのメリット/デメリット
スレッドと似た仕組みとして、fork()による子プロセスの生成があるが、スレッドを使うことによる利点がある。
かなりザックリとまとめると、
メリット
デメリット
- スレッド間の同期処理が面倒
- 利用するライブラリがスレッドに対応している必要がある
サンプルプログラム
こちらから引用。
#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
参考文献
参考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言語, プログラミング
カテゴリー: C言語 | コメントはまだありません »
2009 年 2 月 27 日
C言語でのHTTPクライアントの実装例です。
以下の手順でリモートのサーバと通信し、データを取得します。
- gethostbyname()によりドメイン名からIPアドレスを引く
- socket() によりソケットを開く
- connect() によりサーバに接続する
- write() でサーバにリクエストを送る
- read() でレスポンスを受信する
- 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サーバを作る」に記載しています。
参考書籍
タグ: C言語, プログラミング
カテゴリー: C言語 | コメントはまだありません »