C言語

2005年06月08日

C言語 コマンド引数

すごく基本的なんだけれど、今まで使う機会も無かったし、避けてたことの1つ。
プログラムを実行するときに、引数として値を渡してやる場合。
似てるけれどJAVAとは少し違います。
まず、以下のような感じ。

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

int argc は、見ての通り数字が入ります。
char* argv[ ] は、ちょっとややこしいですが、言うなれば、
char** argv になりますね。
文字列の配列。って事です。

argc は、最低数は1になります。で、つまり必ず argv[0] は中身があるということになります。
中身はって言うと、実行させたときのプログラムパスになります。

$ gcc -o test test.c
$./test
argc:1
argv[0]:./test

になるわけです。
ソースの方は、

int main(int argc , char* argv[ ]){
printf("argc:%d\n" , argc);
printf("argv[0]:%s\n" , argv[0]);
}

基本的には引数と引数の区切りは「半角スペース」です。以下例。

// ./test
int main(int argc , char* argv[ ]){
int i;
printf("argc:%d\n" , argc);
for(i = 0; i < argc; i++){
printf("argv[%d]:%s\n" , i , *(argv + i));
}
}

[ 実行結果 ]
./test "aaaa bbbb ccccc" "dddd,eeee,fff"
argc:3
argv[0]:./fsearch
argv[1]:aaaa bbbb ccccc
argv[2]:dddd,eeee,fff


このように「 " 」でくくってやると1つの文字列として認識してくれるようです。


campanella_77 at 18:44|この記事のURLComments(2)TrackBack(1)

2005年05月28日

C言語 ポインタ変数にNULLを入れると

ポインタ変数に、NULLを入れると、実際には「 0 」が代入されます。

int main(void){

int i;
char** array = (char**)malloc(8 * sizeof(char*));
*(array + 0) = "aaaaaaaaa";
*(array + 1) = "bbbbbbbbb";
*(array + 2) = NULL;

for(i = 0; i < 3; i++){
printf("%d:%d:%s\n" , i , *(array + i) , *(array + i));
}
printf("\n");
*(array + 0) = NULL;
*(array + 1) = NULL;

for(i = 0; i < 3; i++){
printf("%d:%d:%s\n" , i , *(array + i) , *(array + i));
}
}


[ 結果 ]

0:134523214:aaaaaaaaa
1:134523224:bbbbbbbbb
2:0:(null)

0:0:(null)
1:0:(null)
2:0:(null)
続きを読む
campanella_77 at 00:25|この記事のURLComments(0)TrackBack(0)

2005年05月18日

C言語 sscanf -2-

sscanf では、「08」といった頭に「0」が付くような文字列もちゃんと
数字に変えてくれる模様。

注意点として、間に文字列が入っているようなパターン。
例としてApacheのログの時間部分を数字として取得する場合を見てみます。
Apacheのログは、月を示す部分が数字ではなく英語の月の名前の頭3文字と
なっています。

09/May/2005:01:24:37

これを、各変数に入れてみます。

int d , y , h , m , s;
char* mon = (char*)calloc(4 , sizeof(char));

sscanf(date , "%d/%s/%d:%d:%d:%d" , 
  &dd , momo , &yy , &hh , &mm , &ss);

  printf("dd:%d\n" , dd);
  printf("momo:%s\n" , momo);
  printf("yy:%d\n" , yy);
  printf("hh:%d\n" , hh);
  printf("mm:%d\n" , mm);
  printf("ss:%d\n" , ss);

[ 結果 ]

dd:9
momo:May/2005:01:24:37
yy:134514530
hh:-1073743512
mm:1073784804
ss:1075068328

どうやらどこまでが文字列か区別できないようです。
半角を開けてやると区別つきますが、それでも yy 以降が変な値
でした。
そこで、

  char* date = "09/May/2005:01:24:37";

  int dd , yy , hh , mm , ss;
  char* momo = (char*)calloc(4 , sizeof(char));
  
  sscanf(date , "%d/%c%c%c/%d:%d:%d:%d" ,
    &dd , &momo[0] , &momo[1] , &momo[2] , &yy , &hh , &mm , &ss);
  printf("dd:%d\n" , dd);
  printf("momo:%s\n" , momo);
  printf("yy:%d\n" , yy);
  printf("hh:%d\n" , hh);
  printf("mm:%d\n" , mm);
  printf("ss:%d\n" , ss);

[ 結果 ]

dd:9
momo:May
yy:2005
hh:1
mm:24
ss:37

もし、このパターンのように文字数が決まっているのなら、このやり方
でやれば、取り出せそうです。


campanella_77 at 00:49|この記事のURLComments(0)TrackBack(0)

2005年05月06日

C言語 HTTPサーバ開発状況 050506

ここ最近、ブログを書く気がおきませんでした。

自作HTTPサーバがうまく進行せずに、それどころじゃなかったのと、K1を見たり映画を見たり。
ファイルからログを取り出して、CSV形式なら分割してメモリに配置する処理がうまくいかず、ずっと悩んでいましたね。

動的なページ一ページにつき、専用の構造体を用意して、さらにそれらのページは動的な要素がいくつあるかカウントして、それぞれのログを保持する。
めんどくさい・・・。
このログ、ポインタのポインタのポインタのポインタ変数を使ってるため、訳ワカメ。
1つの動的ページに、カウンターがある場合。BBSがある場合。両方ある場合。その他の動的な処理がある場合。等々。

BBSの場合は、ログデータすべてを、各行に分け、さらにCSV区切り文字で分け・・・。
まぁ、めんどくさいし、無駄な処理かもしれませんが、その方が後々スピードアップも図れそうなので。

今回Apacheより遅ければ、作る意味がないのでまずはどれだけHTTPプロトコルに則っているか。は、2の次です。

どれだけはやく処理できるか。
どれだけいじれるか。

が、ポイントとしてやっているわけで、いじれるか。っていうのが、たとえばDoSアタックらしき攻撃を受けたら、3分スリープする。とか、終了させてしまう。とか、管理者にメールを出す。とか、再起動なしにアクセスリストを修正したり等々。

はたまた、静的なページの処理はApacheの軽く3倍はあるので、画像ファイル専用のサーバにするとか。

色々な案はあります。


それもこれも私が飽きるかどうかにかかっているので。(^ ^ ;ゞ
campanella_77 at 19:19|この記事のURLComments(0)TrackBack(0)

2005年05月05日

C言語 構造体 -4-


構造体を複数用意してまとめようかと思ったのですが、どうも
うまくいかなかったりしたのですが、一応、希望通りの動作を
するようになったので、メモっておきます。

2パターンありますが、1つ目はよく(?)陥るミス。
2つ目が一応成功パターン。




文字列を格納する構造体があり、その構造体を複数個配列以外
の手段でまとめて用意したい場合。


続きを読む
campanella_77 at 09:31|この記事のURLComments(0)TrackBack(0)

2005年05月04日

C言語 構造体 -3-

前回、構造体の集合体を配列を用いて操作しましたが、
どうもしっくりこないので、他の型と同じように、
ポインタで操作してみました。
構造体の場合は、構造体ポインタ変数が普通の(?)
変数と同じように扱われてしまうので、構造体のポインタの
ポインタを用いました。



typedef struct testStruct{
  char* str;
}testStr , *testPStr;
//**************** main *****************************
int main(void){

  int i;
  testStr ts;     // 構造体 testStr を用意
  testStr* tsp;   // 構造体 testStr のポインタ変数を用意
  /* ↓これは?? */
  testStr** tspp = (testStr**)calloc(10 , sizeof(testStr*));
  testStr* tsppt;
  
  /* 以下は普通の構造体の使い方 */
  ts.str = "aaa";
  printf("tsp.str:%s\n" , ts.str);
  
  /* 同じ構造体を複数使いたい場合 */
  printf("tsのアドレス:%p\n\n" , &ts);
  for(i = 0; i < 10; i++){
    tsp         = &ts;
    *(tspp + i) = &ts;
    printf("tsp         :%p\n" , tsp);
    printf("*(tspp + i) :%p\n" , *(tspp + i));
    /* 以下はコンパイルエラーになる */
    // printf("*(tspp + i)->str:%s\n" , *(tspp + i)->str);

    /* 1回代入してからならOK */
    tsppt = *(tspp + i);
    printf("%s\n\n" , tsppt->str);
  }
}

よくわかりませんが、一度ポインタをポインタ変数に
代入してからでないと、コンパイルエラーになってし
まい、やむなく上記の方法でやっています。

なんかもっとうまいやり方がありそうですが、検索して
もなかったのでこの方法で。

注意しなければならないのが、メモリの確保です。

 testStr** tspp = (testStr**)calloc(10 , sizeof(testStr*));

このように確保してから、代入しました。

で、

*(tspp + 2)->str

のようには、アクセスできないようです。

tsppt = *(tspp + 2);
tsppt->str; // ←これならOK

続きを読む
campanella_77 at 15:13|この記事のURL

C言語 構造体 -2-

基本的に私は、C言語でほとんど配列を使ってこなかったので
配列の使い方がよくわからないのですが、前回の構造体を
複数用意したい場合は、配列が簡単そうです。


typedef struct testStruct{
  char* str;
}testStr;
//**************** main **********************
int main(void){

  int i;
  testStr ts;     // 構造体 testStr を用意
  testStr* tsp;   // 構造体 testStr のポインタ変数を用意
  testStr tsa[10];   // 構造体 testStr の配列を用意
  
  /* 以下は普通の構造体の使い方 */
  ts.str = "aaa";
  printf("ts.str:%s\n" , ts.str);
  
  /* 同じ構造体を複数使いたい場合 */
  for(i = 0; i < 10; i++){
    tsa[i] = ts;
    printf("%d:%s\n" , i , tsa[i].str);
  }
}

[ 実行結果 ]

ts.str:aaa
0:aaa
1:aaa
2:aaa
3:aaa
4:aaa
5:aaa
6:aaa
7:aaa
8:aaa
9:aaa

campanella_77 at 14:35|この記事のURLComments(0)TrackBack(0)

C言語 構造体 -1-

構造体の仕組みが、いまだによくわからないので
ちと、実験。


typedef struct testStruct{
  char* str;
}testStr;
//**************** main *************************
int main(void){

  int i;
  testStr ts;   //構造体 testStr を用意
  testStr* tsp; //構造体 testStr のポインタ変数を用意
  
  /* 以下は普通の構造体の使い方 */
  ts.str = "aaa";
  printf("ts.str:%s\n" , ts.str);
  
  /* 以下はコンパイルエラーにならないが */
  /* 実行させるとメモリ違反になる       */
  //tsp->str = "bbb";
  //printf("tsp->str:%s\n" , tsp->str);
  
  /* 以下のやり方ならOK */
  tsp = &ts;
  printf("tsp->str:%s\n" , tsp->str);
  
}

★上の例で、「tsp」は、構造体のポインタを格納する変数。
で、ポインタで構造体を操るときは「 -> 」演算子を用いる。

★ただし、構造体のポインタ変数に構造体のポインタを格納
してからでないと操れないっぽい。


campanella_77 at 14:20|この記事のURLComments(0)TrackBack(0)

2005年05月03日

C言語 strtok関数は便利か?

strtok関数 は、文字列を指定された「文字」で
分割してくれます。
PHPでいう「split関数」に似ていますが、ちょっと注意
が必要。

まずは、「strtok関数」は、与えられた文字列に含まれる
指定された「文字」が見つかると、その「文字」を「ヌル」
文字に変え、その「ヌル」までの文字列の先頭のアドレスを
返します。

また、見つからないと「NULL」を返しますが、一度分割さ
せたい文字列を渡すと、2回目以降は「NULL」を指定すると
次の指定された「文字」を探して「ヌル」に変えます。


// 1回目
temp = strtok(str , ",");

// 2回目以降
while(1){
  temp = strtok(NULL , ",");
  if (temp == NULL)
    break;
}


分割させたい文字は、「 " 」で囲みます。
これは、1つだけでなく複数指定できるからです。
「 , 」と「 - 」で分割したい場合は、
",-"
となります。

2回目以降は、「NULL」にすると「strtok関数」内の
変数にどこまで検索したかを示すアドレスが保持され
るんだと思う・・・(自信なし)。
よって、スレッドなどでこの関数を使うと、別スレッド
がその保持した値を上書きしてしまう(と思う(汗))。


ま、ここまではどーでもいいんですけど、注意すること
として、


続きを読む
campanella_77 at 02:32|この記事のURLComments(1)TrackBack(0)

2005年05月02日

C言語 関数ポインタ -3-


C言語 関数ポインタ -2- では、関数ポインタ変数を
宣言するときに、引数の型や個数を指定していましたが、
以下のようにすることも出来るようです。

///////// ユーザー定義関数 ///////////

//*********** func1 *****************
char* func1(char* data , int num){
  printf("func1 の第二引数もうけとれる:%d\n" , num);
  printf("これはfunc1内です\n");
  return data;
}
//*********** func2 *****************
char* func2(void){
  printf("これはfunc2内です\n");
  return "あいうえお";
}
//*********** func3 *****************
char* func3(int* num){
  printf("これはfunc3内です\n");
  char* str = (char*)malloc(16 * sizeof(char));
  snprintf(str , 16 , "%d" , *num);
  return str;
}
//**************************************

//*********** funcfunc **************
char* funcfunc(char*(*pfunc)( ) , void* arg){
  int no = 22;
  printf("ここは funcfunc内です\n");
  char* str = pfunc(arg , no);
  return str;
}

///////// メイン関数 ///////////

int main(void){

  char* returnValue;
  
  returnValue = funcfunc(func1 , "bbbb");
  printf("func1の戻り値:%s\n\n", returnValue);
  
  returnValue = funcfunc(func2 , "");
  printf("func2の戻り値:%s\n\n", returnValue);

  int no = 5;
  returnValue = funcfunc(func3 , &no);
  printf("func3の戻り値:%s\n\n", returnValue);
  
  return 1;
}



続きを読む
campanella_77 at 04:02|この記事のURLComments(0)TrackBack(0)

2005年05月01日

C言語 HTTPサーバ開発状況 050501

起動時に同ディレクトリ内にある、ファイルを読み込んでメモリに格納しておき、リクエストがあるとそちらを出力するような仕様にしました。
が、静的ファイルと動的ファイルと別の処理をさせるため、ややこしい・・・。

一応、静的ファイルを出力する部分は完成。
静的ファイルの場合は、ファイルから読み込んだ時点で、HTTPヘッダとファイルバイト数を16進数で表現した値を、付け足して格納。
リクエストがあった時点で一気に出力。

このおかげで、ホスト名を取得しログを保存しているにもかかわらず、 1600 #/sec という結果をたたき出せるようになりました。

しかし、使用メモリ量を見てみると、アクセスがある度に増えていく。
プログラム行数は数千行に達し、この時点で規則性なく関数を色々な別ファイルに移動させてしまっていた後だったので、バグ取りに時間がかかってしまいました。
結局、関数内で確保したメモリでエラーを返す場合に、解放していなかったのが原因と判明。
この関数は必ず成功する。なんてつもりで作っていると後で痛い目を見る。





アクセス拒否等の仕様も取り入れたいので、もう少し遅くなるかもしれませんが、まぁまぁの出来って感じでしょうか。
campanella_77 at 22:46|この記事のURLComments(0)TrackBack(0)

C言語 sendで送る前に相手がいなくなったら

ソケットによる通信途中、send関数によって送信する前に相手が何らかの理由でソケットを閉じてしまった場合、send関数は「 -1 」を返すようです。

sleep(5);
printf("sendの戻り値:%d\n" , send(sock , sendData , strlen(sendData) , 0));

ブラウザでアクセスして、5秒以内にブラウザを終了させると、

-1 という値が返ってきてました。
campanella_77 at 04:57|この記事のURLComments(0)TrackBack(0)

C言語 ディレクトリ内のファイルリスト

C言語でディレクトリ内のファイル・ディレクトリ名を
取得するのは、以下の方法で。

dirent.h をあらかじめインクルードしておくこと。

  DIR* dir;
  struct dirent* dp;
  
  if (NULL == (dir = opendir("./"))){
    printf("ディレクトリを開けませんでした\n");
    exit(1);
  }
  for(i = 0; NULL != (dp = readdir(dir)); i++){
    printf("%d:%s\n" , i , dp->d_name);
  }
  closedir(dir);

取得できるファイル名は、名前順やサイズ順や更新日順
とは無関係のよう。
自分自身を示す「 . 」や1つ上を示す「 .. 」
も取得される。

campanella_77 at 04:17|この記事のURLComments(0)TrackBack(0)

C言語 Apacheではホスト名を取得しているのか

今までの実験結果から見ると、接続してきたクライアントの
ホスト名を取得させると、かなりオーバーヘッドが出る。と
いうのが判明しました。
後にまとめた結果を載せますが、では、「Apache」なんかは
どうだろうかと思って調べてみると、「Apache」では、
設定によりIPアドレスによるアクセス制限はもとより、ホス
ト名でも拒否できるらしい。

「Apache」がどのようにホスト名を取得しているのかわかり
ませんが、それは私のHTTPサーバのように、gethostbyaddを
使っているのかもしれませんし、別のものかもしれませんし、
特別なものを使ってるかもしれませんし。
いずれにせよ、私のネットワーク外のどこかから教えて
もらいにいっているとは思うので、その解答が送られてこな
いことには、取得できないわけです。

この問い合わせにかかる時間がオーバーヘッドになってしま
っているのですが、「Apache」は毎回ホスト名を取得している
のでしょうか。
「Apache」のログには接続元のIPアドレスは記載されるものの
ホスト名は記載されていません。
PHPやCGIでホスト名を取得するような処理をしない限り、
ホスト名を取得は意味がないような気もします。
そこで、「Apache」の「http.conf」の設定で、アクセス設定
にホスト名で指定して実験してみました。

Deny from .jp

このようにしておくと、「.jp」を含むホスト名のクライアント
は、アクセスできません。
この設定が有効であれば、「Apache」は何らかの方法でホスト
名を取得しているはずです。
また、速度はどうでしょうか。

実は、単なるHTMLファイルの場合の速度測定は、ばらつきがあ
りすぎてどれが本来の速度かわかりません。
320 #/sec 辺りが多いのですが、時には 500 #/sec なんて値
もたたき出します。
よって、比較的値が安定しているPHPへのアクセスで実験しました。

Deny from .jp
と指定したときとしてないときで、速度にどう変化が出るか。

結果はどちらも同じでした。
つまり、「Apache」はデフォルトでホスト名を取得しているよう
です。

と、いうことは、以前の速度測定の時の「 500 #/sec 」という
結果は、ホスト名を取得してなおかつこの値だよ。と。
もちろん詳細なログも取得しているわけですし、それを踏まえて
私の作成するHTTPサーバは、この値を下回るようなものが出来
上がったとしたら、そんだったら「Apache」を使った方がいい
ンじゃないか。と、なるわけで・・・。

いやはや・・・。

(ま、娯楽で作ってるからいいんですけど・・・)

次に、我がHTTPサーバを使って、色々な処理をした場合の速度
の変化についてまとめておきます。




続きを読む
campanella_77 at 01:41|この記事のURLComments(0)TrackBack(0)

2005年04月30日

C言語 スレッド作成までの時間

スレッド作成には時間がかからない。なんて書かれてたので、受信したデータ解析は新たに専用のスレッドを作成して、そちらで解析。で、作成した側(これもスレッドなんだけれど)は、そちらの処理如何に関わらず、データをクライアントに送信する。
これなら、いくら解析やらログの記録に時間がかかろうが、送信⇒ソケットをクローズが一定の時間になるだろうと思い、さっそく実験。

本体が起動するとソケットの準備をして、数個のスレッドを作成。
各スレッドはacceptしてクライアントからの接続を待ち受ける。
クライアントがアクセスし、データを受信しおわると、さらにスレッドを立ち上げる。
立ち上がったスレッドは受信したデータを渡され、(とりあえず今回は)1秒間スリープしたあと消える。
スレッドを作成側のスレッドは、そのまま送信もせずにソケットをクローズ。

この受信⇒スレッドを作成という処理がなかった場合は、「 1600 #/sec 」。

では、実験結果は。

「 1000 #/sec 」・・・・。

だいぶ遅い・・・。
スレッドを作成するまでの手順が結構時間かかってるんでしょうか。


振り出しにもどる。続きを読む
campanella_77 at 10:09|この記事のURLComments(0)TrackBack(0)

C言語 HTTPサーバ開発状況 050430

ある程度の基本機能を備えたHTTPサーバが出来てきましたが、機能をつけるごとに処理速度が遅くなる。

ログや動的なページを表示させようとすると、どうしても効率の悪い処理を行わざるを得ないので疾駆八区。

そんな中で、各まとまった処理を関数化させてデバッグや見やすいプログラムにはなってきたとは思いますが。


今まで2600#/sec なんていう記録が出てましたが、ログを記録させるだけで1000を切る始末。
ログ処理や受信データ解析処理はさらにスレッドを立てて、そちらで処理させるか思案中。

ところで、クライアントからアクセス・データの受信を行ったら即ソケットをクローズさせた場合、どれくらいの結果が出るかやってみました。

結果、3600 #/sec (さらに、受信もしないで接続後即ソケットをそのスレッドすると、 4700 #/sec)
どうやらこの値を目安に処理速度が速いか遅いか目安にした方が良いかもしれません。
目指せ1500以上で動的ページの出力。
campanella_77 at 09:09|この記事のURLComments(0)TrackBack(0)

2005年04月29日

C言語 排他処理

CGIを学びはじめると、ファイルの書き込みについての項目に必ずといってもいいほど排他処理に関しての項目があると思います。

基本的には、複数のプロセスが参照するようなファイルに書き込みをする場合は、書き込んでいる間、ファイル内の値が不明なため書き込んでいる間は他のプロセスが参照・書き込みできないようにする。
と、いった処理が必要になってくるようなことが書かれています。

ファイルの書き込みに関してはOS任せなので、意識的にプログラマが書き込むまでのタイミングを図ってやる。という処理をすることになります。
flockしかりセマフォやディレクトリの有無等々、色々なやり方が議論されているようです。

今まで「ab」により私の作成しているHTTPサーバに短時間のうちに高アクセスさせている実験を行っていますが、「ab」の動作がどのような法則があるかわからないので何とも言えませんが、カウンター機能をつけてもうまく動作しているようです。
少なくともカウンターを記録するファイル内の値が「0」もしくは「無し」にはなっていないようです。

1つの実験として、アクセスがあるとログにカウントしていく以外に、メモリ上のグローバル変数の値もカウントしていく。
といった処理も同時に実行させるようにして「ab」でアクセスさせます。

# ab -n 10000 -c 10

として実行させました。
処理が終わるのに10秒程。
さて、メモリ上のカウントはというと「10008」。
だいたい1秒間に約1001回アクセスがあった計算になります。
で、ファイルの方の値はというと「10008」と、見事に一致しました。
同じタイミングで(正確に言うとファイルに書き込んだ後メモリ上の値もカウントアップ)していますので、厳密な検査とは言えないかもしれませんが、まぁ、壊れてはいないかなぁ。と。

まぁ、1秒間に1000回どころか1日に1000アクセスすらないサイトがほとんどだと思われるので、まぁ、あんまり気にしなくていいかもしれませんが。


続きを読む
campanella_77 at 12:06|この記事のURLComments(0)TrackBack(0)

C言語 HTTPサーバ -ファイルへの保存がネックに-


前回
のやり方だと、アクセスの度にファイルをオープンしなければならないので、時間がかかるような気もします。
よって、サーバ起動時にファイルをオープンしておき、アクセスがあったらファイルを巻き戻して読み込み、加算。出力した後、保存。ファイルは開きっぱなし。
と、いう処理にしてみました。
ファイルをオープンするモードは「r+」。
これなら、サーバ起動中であってもカウンターファイルを別のプロセスが開くことが出来ます。

さっそく書き直してテスト。

1200 [#/sec]

さっきよりだいぶ速度が上がりました。
この段階で、もし仮にカウンターがない場合の速度は・・・。

2300 [#/sec]

倍ぐらい速いですね。

読み込んで数値にも変換せずにそのまま出力・保存した場合は、

1250 [#/sec] ※そんな変わらない




campanella_77 at 01:29|この記事のURLComments(0)TrackBack(0)

2005年04月28日

C言語 send関数のメモと「ab」の動作

send関数は送信すべきバイト数を超えて指定したとき、バッファオーバーフローを起こしているか、余分な分をヌルで埋めて送信する。

どちらにしろ指定した値のみ送信する。と、いうよりは、指定したバイト数を送る努力をするようだ。

パケットキャプチャーで見てみるとヌルで埋められているが、オーバーし始めの部分でヌル以外の文字も送っている。
よって、もしかしたらバッファオーバーフローを起こしているのかもしれない。

この辺はよくわからないが、あてずっぽにバイト数を指定しない方が良いかもしれない。

次に速度測定に使っている「ab」だが、

ab -n 1 -c 1 ←2回接続してくるが、最後の1回は接続のみだけ。

ab -n 2 -c 2 ←4回接続してくるが、データを送信してくるのは2回だけ。

ab -n 5 -c 2 ←8回接続してくるが、データを送信してくるのは6回だけ。

ab -n 2 -c 10 ←20回接続してくるが、データを送信してくるのは10回だけ。
※さらに10回データを送信する接続があった後はずっと接続のみ。

ab -n 10 -c 3 ←15回接続してくるが、データを送信してくるのは12回だけ。

ab -n 10 -c 2 ←12回接続してくるが、データを送信してくるのは10回だけ。


ab -n 100 -c 10 ←110回接続してくるが、データを送信してくるのは109回だけ。

ab -n 1000 -c 100 ←1053回接続してくるが、データを送信してくるのは1052回だけ。

ab -n 100 -c 1000 ←162回接続してくるが、データを送信してくるのは108回だけ。

続きを読む
campanella_77 at 22:48|この記事のURLTrackBack(0)

C言語 マルチスレッド時Ctrl + Cのシグナル処理

Ctrl + C を押して強制終了させる前に、データの保存等が出来るようにシグナルを受けとった後に、色々処理できる仕様にして作ってきましたが、どうもマルチスレッドにさせたときはおかしな動作をするようになる。

マルチプロセスの時は正常に処理されましたが、マルチスレッドだとセグメンテーション違反が起きたり、反応しなくなったり(まぁ、どうせ終了させるのだから、特に問題はないのでほっといてもいいのだけれど)悩んでいました。

なぜ、セグメンテーション違反になるのかわからなかったので(終了させたスレッドを終了させようとしたため?)、とりあえずうまくいくように出来たので、いつものように忘れないようにメモっておく。
ちなみに、詳細は載せないので私にしかわからないとは思う。

if (sigNum != 2 && sigNum = 14)
exit(1);

これをシグナルを受けとった後に動作させたい関数内の最後に記述しておく。

あと、SIGINTを受け取るセッティングはスレッド関数内で記述しないと、そのままプロセスが何も受け付けなくなるようです。
原因は不明。受け付けるときもあれば、受け付けなくなったりする。

campanella_77 at 05:41|この記事のURLTrackBack(0)

2005年04月27日

C言語 可変引数 -1-

可変引数について実験してみました。
stdarg.h が必要です。

今回紹介するやり方の注意点として、「いくつ
引数があるか関数に教えてあげる必要がある」
ということです。

以下の例では、 int num の部分が渡す
引数の数を入れる部分で、この引数は、数に数
えません。

まず、va_list型 を用意します。

可変引数を扱う前にまず、可変引数の1個前の
引数の名前を va_start の第二引数に
渡します。第一引数は先ほどの va_list型
の引数です。

関数内部では引数の数が不明らしいので、ループ
でとり出すときに、外部から与えられた個数を
目安にしてあげないとダメらしいっす。

で、ループの中で1個1個取り出してます。
取り出す役割を担っているのが va_arg 
です。
先ほどの va_list型 を、第二引数に
取り出す型を指定するようです。
下の例では、「char*」として取り出してます。
ここいら辺は foreach に似てますね。

最後に va_end で可変引数の取り扱いが
終了したことを知らせます。


続きを読む
campanella_77 at 22:00|この記事のURLComments(0)TrackBack(0)

C言語 一定時間ごとに処理をさせたい

前回メインのプログラムを低負荷でブロックさせる方法
として、「pthread_join( )」を使うと書きましたが、
プログラムを一時的に停止する事をスリープなんて言う
らしいのですが、スリープ用の関数もあります。

「sleep関数」がその代表だと思うのですが、この関数
使ってみるとCPU使用率がめちゃめちゃ上がる。

で、「pause関数」という関数を使うと超低負荷でプロ
グラムを停止させることが出来るようです。
この関数は引数を必要とせず、プログラムにシグナルが
渡されるまでブロックし続けます。

逆に言うと何かしらシグナルを渡さない限り永久的に
プログラムが停止してしまいます。

これらを利用して、一定時間ごとに同じ(でなくてもい
いが)処理をさせる要望が高いみたいなんで、ある程度
希望が叶いそうなプログラムを書いてみました。


続きを読む
campanella_77 at 11:35|この記事のURLComments(3)TrackBack(0)

C言語 スレッド-1-

gcc で、スレッドを使うようなプログラムをコンパイルするときは

gcc -o thread.exe thread.c -lpthread

とする。「 -lpthread 」が必要。

これを忘れて2時間悩んだ・・・。
campanella_77 at 00:37|この記事のURLComments(0)TrackBack(0)

2005年04月26日

我が輩の作成したHTTPサーバ vs Apache

C言語で作成したHTTPサーバをマルチスレッドにさせてみました。
1からやり直したので、結構時間がかかりましたが、それぞれの
処理を関数化したのですっきりと書くことが出来たので、
まぁ、いいかな。と。

ただ、正しく処理し切れてるか自信ありません。
途中で飽きて来ちゃって・・・。
さらに、今回初めて(JAVAではあるけど)スレッドを取り入れた
のでもう何がなんだか訳ワカメです。

スレッドのやり方に関しては次に回すとして、さっそく恒例の
速度競争を実施。

ま、たいして役に立つわけでもないけれど一応達成感を味わうため
の私個人の恒例になってますわ。

えー。対決内容は前回と同じ、我が輩のHTTPサーバとApacheで
同じものを出力した場合、どちらがどれくらい速いのか。です。
今回は、Apache側は単にHTMLファイルを出力するだけの参加。
PHPやCGIの結果は前回のを参照してチョ。

我が輩のHTTPサーバも同じものを出力します。
ただ、我が輩の方は起動時に出力ファイルを読み込んで、出力
する場合は、メモリ上のそれを出力しています。
読み込む手間がない分速いだろうと。


続きを読む
campanella_77 at 10:38|この記事のURLComments(0)TrackBack(0)

2005年04月25日

C言語 最速奪回


以前 色々な言語を使用して、ファイルから指定された文字列がいくつあるかとか、指定された文字列を含む行を取り出すとかを競争したわけですが、結局C# が1位で一段落付いていました。

あの頃は、私もC# 信者であったわけで、その結果には重々満足すると共に、でもC# より C の方が遅いのはもっと速いやり方があるんだろうな。なんていう思いも心の隅にあったわけです。

で、今やC言語ユーザーになりつつあるわたくしにとって、C言語名誉挽回といくためにまたあれこれ奮闘しておる次第。
C# のようにファイルを一気にメモリに読み込む方法を模索していましたが、Linuxでは確かにこの方法だと速い。⇒ ここいら辺参照

で、Windowsでやってみるとそんなに速くない。

何となく予想が付くとは思いますが、バイナリファイルとして読み込んだら速いんじゃないかと思い、なになにWindowsとLinuxではバイナリファイルの扱いが違う。フムフム。と、色々調べる。




続きを読む
campanella_77 at 18:40|この記事のURLComments(0)TrackBack(0)

C言語 bindがうまくいかない


そろそろプログラムも飽きてきたところなんで、専門(?)でもあるFLASHやブログ改造や作りかけのサイトページやページデザイン等々、やらなきゃならないものがたまっているので、そちらに移行したいのですが、そっちもやる気がでない。
よってこのままC言語 de HTTPサーバ造りを続けようかな。なんて優柔不断な思いに駆られている今日この頃。C# をやるっていっていた気迫はどこへやら。

元々、C言語なんて金輪際やらん!と、WinSockを実験していたとき思っていたのにLinux環境でやり出してからとんとん拍子で学習が進んでいくので、ここまで深くC言語にはまりこんだのではないだろうかと思いつつ、CとLinuxの相性の良さに感心しながら書いているわけで・・・。


本題。

ソケットを使ったネットワークプログラムをデバッグを繰り返しながら作っていると、ときどき「bind関数」が成功しない時があります。

大抵私の環境では「セグメンテーション違反」によって強制的に終了させられたり、思いがけないエラーなんかの時のあと数十秒ほど、「bind」がうまくいかないようです。
今までは、成功するまでループさせて(sleepを交えながら)いましたが、ん〜なことせんでも一発で成功させられる呪文を見つけたので、メモっておきます。

確かにこの呪文が書かれたお札をプログラム中しかるべき所に貼っておくと、失敗することが無くなりました。(使用者からのお手紙から抜粋)

int yes = 1;

setsockopt(sock , SOL_SOCKET,
SO_REUSEADDR , (char * )&yes , sizeof(yes));


これをソケットの設定が終わって「bind」する直前にでも貼っておいてください。


campanella_77 at 06:01|この記事のURLComments(0)TrackBack(0)

C言語 関数ポインタ -2-

前回 のような使われ方はあまり無いと思います。
実際は、関数に関数ポインタを渡すときでしょう。

以下の関数を見てください。

char* funcfunc(char* (*pFunc)(char* str) ){
  printf("これは fucnfunc 内です\n");
  return (*pFunc)("引数はここで渡す");
}

前回の例を使って説明すると、

printf("%s\n" , funcfunc(func));

結果は、

これは funcfunc 内です
これは func 内です
引数はここで渡す


以上。関数の引数に関数ポインタを渡したいときの
例でした。

campanella_77 at 00:37|この記事のURLComments(0)TrackBack(0)

C言語 関数ポインタ -1-

以下のような簡単な関数を考えてみます。

char* func(char* str){
  printf("これは func 内です。\n");
  return str;
}

引数で受け取った文字列をそのまま返す関数です。
ただ、わかりやすいように関数内がちゃんと処理されているのを
目に見える形で出力するために「これは func 内です」という出力
も加えてあります。

さて、これを使うにはプロトタイプ宣言(main関数より先に定義
した場合は必要ありませんが)が必要になってきますが、以下の
ような感じになるでしょう。

char* func(char* str);

これをふまえた上で、

変数や構造体と同じように、関数もメモリのどこかに保存される
でしょうから、そのアドレスがあるはずです。

関数をポインタで操るにはどうしたらいいか実験してみました。
以下を見てください。

char* (*myFunc) (char* str);

先ほどのプロトタイプ宣言ににていますね。
違うのは、「func」という関数名が「myFunc」になっていて、かつ
「( )」で囲まれていて、さらに「 * 」が付いています。

えっと、これが変数の宣言ならぬ関数ポインタの宣言です。
この「 myFunc 」に関数のポインタを代入して操作すること
になります。
ただし、今回の例でいうとこの関数ポインタ変数に代入できることが
出来る関数ポインタは、「戻り値」が「cha*」で、「引数」が
「char*」型のもの「1個」のみ。
と、なります。

わかりにくいので具体的に見ていくと、



char* func(char* str){
  printf("これは func 内です。\n");
  return str;
}

char* func2(char* str){
  printf("これは func2 内です。\n");
  return str;
}

void main(void){

  /* 関数ポインタ変数の宣言 */
  char* (*myFunc) (char* str);
  
  /* 代入                   */
  myFunc = func2;
  
  /* 処理させてみると・・・ */
  printf("%s\n" , myFunc("func2を代入した場合"));
  
  /* 同じ方を返し同じ引数で */
  /* あれば、別の関数も代入 */
  /* 出来る                 */
  myFunc = func;
  
  printf("%s\n" , myFunc("funcを代入した場合"));
}
  
続きを読む
campanella_77 at 00:32|この記事のURLComments(0)TrackBack(0)

2005年04月24日

C言語 構造体 -2-

前回、構造体をポインタで操作するときに構造体内部変数を
使うときは「ドット」ではなく「 -> 」を使うと書きました。

そんな紛らわしいことする時ってあるの?

なんて思うかもしれませんが、あります。
おそらく多くは関数に渡したいときではないでしょうか。

関数外で用意した構造体を関数に渡して構造体の中身を色々
処理してもらう場合です。

前回の例で見てみます。

まず、以下のような関数を用意します。

void Passwordchange(client* funcUser , char* newPass){
  
  funcUser->pass = newPass;

}

void main(void){
  client user01;  /* 宣言 */

  user01.id   = "suzuki";
  user01.pass = "0123456";

  /* 関数前 */
  printf("IDは%s\nパスワードは%s\n" ,
    user01.id , user01.pass );
  
  /* ここから付け加え */
  Passwordchange(&user01 , "789");
  
  /* 関数後 */
  printf("IDは%s\nパスワードは%s\n" ,
    user01.id , user01.pass );
}


[ 実行結果 ]

IDはsuzuki
パスワードは0123456
IDはsuzuki
パスワードは789


関数内部で変更した結果が、関数外部でも保持されています。
PerlやPHPでいう参照渡しですね。

campanella_77 at 21:12|この記事のURLComments(0)TrackBack(0)

C言語 構造体 -1-

今まで構造体について学ぶのを避けてきましたが、だんだん
避けては通れなくもなってきたので、ちょっと実験。

まず、構造体を見て思ったこと。

オブジェクト指向のクラスにそっくり。
いや、クラス内部でメソッド(関数)を定義できなくした感じ。
メンバ変数だけ定義できる。

また、その構造体を使いたい場合は、クラスの場合は、
「new演算子」を用いてインスタンス化させますが、構造体の
場合は、変数の宣言に似てる(ただし、変数が初期化できるの
に対して、構造体変数(?)はそもそも代入が出来ないので
初期化は出来ませんが・・・)。

等々色々ありそうです。
あとクラスも似てますが、PHPやPerlの連想配列にも似てます。

C言語ではデフォルトで連想配列という概念が無いので、同じ事を
するには構造体を使うことになると思います(ただし、めんど
くさい)。


あれこれ文字で言ってもわかりづらいので、実際にやってみます。

まず、構造体を作りたい場合は、関数外部で

typedef struct clientData{
  char* id;     /* IDを格納        */
  char* pass;   /* パスワードを格納 */
}client;

こんな感じで定義します。

使いたいときは、

void main(void){
  client user01;  /* 宣言 */

  user01.id   = "suzuki";  /* JAVAのメンバ変数に   */
  user01.pass = "0123456"; /* 代入するのと似てる   */

  printf("IDは%s\nパスワードは%s\n" ,
    user01.id , user01.pass );
}

[ 実行結果 ]

IDはsuzuki
パスワードは0123456


JAVAでのオブジェクト内のメンバ変数を扱うのと同じように、
「.(ドット)」を使っていますね。
ドットシンタックスなんて言います。

構造体について学んでいくと、「ドット」ではなく「->」が
使われている場面に遭遇すると思います。
これは構造体をポインタで操作するときに使われるようですね。
たとえば、先ほどの例をつかって説明すると、


続きを読む
campanella_77 at 18:04|この記事のURLComments(0)TrackBack(0)
最近撮った写真
campanella
What's campanella
ライブカメラ公開中
kao.gif
訪問者数