「Web2.0とC10Kに関する数々の誤解」の誤解

前エントリWeb2.0とC10Kに関する数々の誤解に関してはいろいろツッコミをいただいた(ありがとうございます).

名無し 『誤読した上にえらそうに微妙な解説するあたり恥ずかしすぎます。』

えらそうで微妙な解説なのはまぁそうなので否定しないが,誤読とはなんのことだろう?
こういうときは今はやりの「スルー力」を発揮するのが大人のインターネットかと思ったけれど,
私のBlogが扱う内容は非常に狭く,さらにそれに対して突っ込もうと思う人の
意見はなにかしらの真実が含まれるはずと考えていたところ,下記エントリがあった.

元記事の人は上でいう 3,6 あたりを書いていて,id:yamaz さんは 3 するなら 4 とか常識だろ,と噛みついているように読めました。.

なるほど,私の前エントリ@ITの元記事に対して噛みついているように
読めるようだ(言われてみればたしかにそう読める).


実際の所は元記事のはてなブックマークのコメントや同僚達との話などから
AjaxやCometなどのWeb2.0的なプログラミングとC10Kに関していろいろ
誤解を受けそうな印象を受けたので,誤解を受けてそうなモノを
(元記事の中の人とか関係なく)ピックアップしてエントリとして
出した次第で,元記事に噛みつくという意図はなかった.


どうも前提条件などの書き方や元記事のフォローする形を取ったのが
悪かったようで,前エントリのはてなブックマークを見るに,さらなる
誤解を生んでしまった感があってBlogを書くのもなかなか難しいと思った(この憶測も誤読だったりして:D).


で元記事に関してフォローしておくと

  • 従来のfork/threadのプログラミング方法はプロセス/Threadが単純増加するので,サーバリソースが足りなくなったりする(yamazが考える@ITの記事の主張)

これはこれであってるので,

  • それはそれとしてC10Kはいろいろ誤解されてる気がするので,例を挙げるので正しく理解しよう(yamazの主張)

という風にもう一度両記事を読みなおしてもらえるとありがたい(今更だが).

さて,あとはてなおやさんからTBがあったので,それにも答えたい.

おおむね同意なんだけど、ここだけちょっと。
"Comet のようにクライアントからの書き込み要求は別Port、あとは大多数の..." というところをもうちょっと詳しく教えてほしい。


実はなにを答えたらいいのか悩んだんだけど,
「お前の言うスレッドやプロセスなどのリソースを消費しない実装方法教えろよ」
と勝手に脳内変換してみる.ちなみに書き込み要求が別PortなのはRailsChatの話でした(本質じゃないけど).

まず私の理解ではlingrがやってるであろうComet用サーバの処理は2つに分かれる.

  1. acceptをひたすらして受け付けたリクエストの初期化処理(認証とか)を行ってコネクションのソケットを管理するだけの処理
  2. なんらかのイベント(書き込みとか)が発生したら格納されたソケットに通知する仕組み

ポイントはいくつかあるかと思うが,まぁ論よりコードということで,
簡単なサンプルサーバを書いてみた(エラー処理とかは適当).

/* 8001ポートに3個接続がおきたらその旨を返すだけのサーバ */
#include <stdlib.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <sys/signal.h>


#define CONNFDMAX 3
#define BUFMAX 1024
#define EVENT_HAPPEN_STR "event happened!\n"
#define DEFAULT_LISTEN_PORT 8001

void
sig_child_handler(int signo){
  pid_t pid;
  int stat;
  while((pid = waitpid(-1,&stat,WNOHANG)) > 0){
    printf("child %d exited.\n", pid);
  }
}

int
main(int argc, char **argv){
  int listenfd, connfd,i;
  int cur_sock = 0;
  int clisocks[CONNFDMAX];
  socklen_t len;
  struct sockaddr_in servaddr,cliaddr;
  pid_t childpid;
  char buff[BUFMAX];

  signal(SIGCHLD,sig_child_handler);
  len = sizeof(cliaddr);
  if ((listenfd = socket(AF_INET, SOCK_STREAM, 0))< 0){
    perror("server:socket error");
    return (1);
  }

  bzero(&servaddr,sizeof(servaddr));

  servaddr.sin_family = AF_INET;
  servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
  servaddr.sin_port = htons(DEFAULT_LISTEN_PORT);

  printf("listenfd: %d\n",listenfd);
  if (bind(listenfd, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0){
    perror("server:bind error");
    return 1;
  }

  if (listen(listenfd, CONNFDMAX) <0){
    perror("server:listen error");
    return 1;
  }

  for(;;){
    if((clisocks[cur_sock] = accept(listenfd, (struct sockaddr *)&cliaddr, &len) )< 0){
      perror("server:accept error");
      return 1;
    }
    printf("accepted client socket fd: %d\n",clisocks[cur_sock]);

    if((childpid = fork()) ==  0){
      close(listenfd);
      /* ほんとだったらここでreadして初期化とかするけど,今回はそのままexit. */
      close(clisocks[cur_sock]);
      exit(0);
    }

    /* ほんとだったらここで子プロセスに渡ったソケットをcloseするけど,今回はそのまま */

    cur_sock++;
    if (cur_sock == CONNFDMAX){ /* イベントが起きた! */
      for(i=0;i< CONNFDMAX;i++){
        /* イベント処理とsocket fdのの後始末. cometはここで再接続用のJSコードを吐く.*/
        write(clisocks[i],EVENT_HAPPEN_STR,strlen(EVENT_HAPPEN_STR));
        close(clisocks[i]);
      }
      cur_sock = 0;
    }
  }
  return 0;
}


詳細はプログラムとコメントを見てもらいたいが,ポイントとしては
下記などがあげられると思う.

1. 1のクライアントから接続に対するaccept処理後,forkやスレッドを
生成させる(並行処理のため).ただそれらは初期化が終わったら速やかに
なくなるので,コネクションが張りっぱなしでもOS内にとどまり続けることはない.
プログラム的にはsig_child_handler()でexitした旨のメッセージが出るので,
forkした子プロセスがなくなりつつも,コネクションが維持できていることがわかると思う.

2. 今回はクライアントが3つ来たらイベント発生というプロセス内で完結する
形にしたが,イベント通知に関してはイベント発生が別プロセスや別マシンなど
だとacceptのBlockから抜け出せないので,別途非同期シグナルなどでイベント
通知の処理をしてあげる必要がある.


あと

それはあまりにも Comet に特化した実装だから特殊と見るべきかなあと。

ということだけど,ChatとかGameとか株価のnotifyシステムなどのインターネットにおける大多数/長時間に渡る待ちのコネクション→イベントによるスモールメッセージの通知システムの1実装としてCometはあるというのが私の認識なので,そんなに特殊な話ではない気がする.


# これで答えになってますか?>はてなおやさん


なお動画のストリーミング配信など常にコネクションを張りっぱなしで
ネットワークにデータを流しっぱなしにする必要があるような場合は,
コネクションを張っている間スレッドなりプロセスを保持する必要がある.
よって@ITの元記事にあるようなことは起こりえる.これの回避に関しては
「こうすればうまくいくんじゃないか?」みたいなのはあるけれど,コードで
実証してないので今の所「あとで書けるかも」の方向で.

(おしまい)

あわせて読みたい

CNET Japan Blog - 江島健太郎 / Kenn's Clairvoyance:Lingr and Comet - 技術解説編

http://blog.japan.cnet.com/kenn/archives/003149.html
lingr江島さんによるlingrの技術解説.

「足あとライブ!」に関するテクニカル・メモを書いてみた

http://satoshi.blogs.com/life/2006/10/post_9.html

UIE 中島さんによる「足あとライブ!」の技術メモ.
上記記事の先の解説ページを元にフルスクラッチでシステムを作ればUIEへの挑戦権が
ゲットできるらしいので,興味ある人はゼヒ.

Unix系プログラミング本3冊

詳解UNIXプログラミング

詳解UNIXプログラミング

  • 作者: W.リチャードスティーヴンス,W.Richard Stevens,大木敦雄
  • 出版社/メーカー: ピアソンエデュケーション
  • 発売日: 2000/12
  • メディア: 単行本
  • 購入: 8人 クリック: 103回
  • この商品を含むブログ (41件) を見る

UNIXネットワークプログラミング〈Vol.1〉ネットワークAPI:ソケットとXTI

UNIXネットワークプログラミング〈Vol.1〉ネットワークAPI:ソケットとXTI

  • 作者: W.リチャードスティーヴンス,W.Richard Stevens,篠田陽一
  • 出版社/メーカー: ピアソンエデュケーション
  • 発売日: 1999/07
  • メディア: 単行本
  • 購入: 8人 クリック: 151回
  • この商品を含むブログ (37件) を見る

UNIXネットワークプログラミング〈Vol.2〉IPC:プロセス間通信

UNIXネットワークプログラミング〈Vol.2〉IPC:プロセス間通信

  • 作者: W.リチャードスティーヴンス,W.Richard Stevens,篠田陽一
  • 出版社/メーカー: ピアソンエデュケーション
  • 発売日: 2000/08
  • メディア: 単行本
  • 購入: 2人 クリック: 30回
  • この商品を含むブログ (14件) を見る
この手の話をするときには欠かせない3冊.ただこの本は世に出てから結構たってて,
今の状況に完全にあってるかどうかは正直わからない.が,オススメなのには変わりない.


これ以外にもし現状に即してて,網羅的に解説してる書籍や文章があるならどなたか教えてください.

yamaz的日常

id:hirose31くんのiPhoneみてワクワクしない人は基調講演みた方がいいかもを読んでさっそく
ジョブズの基調講演を見てみた.


感想: わー、こんな楽しげなの毎年やってたのかー.もっと早く教えてくれよぅ.


私のようにPCや携帯をビジネス用途でしか使ってない人で,
Apple製品のキュートさに気づいてない人はとても多いと思うので,
マカーな人はこの手の動画の存在をちゃんと毎回アピールして欲しいと思った.ズルい!

ちなみにこの動画を見た後,ただちにMacBookを買いに渋谷のAppleStoreに向かった.
今使ってるLet's Note Yシリーズに比べ,あまりのデカさと重さに購入は断念したけど,
結構危なかった.

あわせて見たい

任天堂株式会社 経営方針説明会
http://www.irwebcasting.com/060607/03/74d18b0400/main/index_hi.htm

53分くらいから任天堂宮本さんによるWiiの記者発表の様子があるけれど,
これもワクワク感が高いので見てない人はゼヒ.