チャットプロトコル (1)

チャットプロトコルを作っています。
前提は、

  1. 1台のサーバで同時に処理できるクライアント数をできるだけ増やす

です。
もちろんサーバーサイドでクラスターとかを組んで分散させるのもいいとは思うのですが、もう少し手軽にやりたいのでサーバー1台で扱える最大クライアント数(セッション数)を増やすことを一番に考えています。

で、初めはUDPパケット単位で非同期に通信できるプロトコルを考えていたのですが、会話パケットがロストしたときに、再送要求を出すとするなら、サーバー側で保持する再送用のパケットキューがルーム単位になるので、それにどれだけのリソース確保しておけばいいのかという問題があって、ちょっと考えたのですが、メンバー数や発言スピード(発言数/秒)にも影響されて『保険』と『無駄』の境目がよく見えなくて、どうも発言パケットを必ず補完することができないし、しようと努力すると無駄なリソースがガンガン増えるので、中途半端な気がして、もうなんかやめました。あとメンバー一覧の取得とかもそうです。
最近は、無線LANの利用者が増えていて、無線LANはパケットロスが頻発するので、これは大問題なんです(たぶん)。
(電子レンジやコードレス電話やクルマの無線なんかのデンパと干渉するらしい……)

だからといって、TCPを使おう! とは思えません。
チャットサーバーというのは『ルーム』というマルキャストグループのようなものを作っておいて、それに対するセッション側からのアタッチ・デタッチと、グループ内のセッションからの会話パケットをグループ中の全セッションへマルチキャストするルーターのようなものと考えています。
ルームに1024のセッションがいて、そのうち1つから会話パケットが届いたら、同じ内容のパケットを1024のセッションに対して送信します。このときOSのTCPソケットはそこへwrite(2)された内容が、そのときちょうど使われている他のソケットへwrite(2)された内容と同じかどうかなんてチェックしないので、非同期に設定されているTCPソケットでは同じデータが少なくとも1024個ほどコピーされて、必要メモリがボコンと増えます。これは接続数と比例するのでよくありません。また、ひとつのプロセスで使えるソケット数にはOSの制限があります。
そこで! 同じデータなら実体はひとつで他はリファレンスでいいはずし、単にパケットロスを防ぎたいだけなので、TCPである必要はないということで、UDP上にマルチキャストを意識したストリーム指向のプロトコル(マルチストリーム?)を作って、そのうえにチャットプロトコルをのせることにしました。
イメージ的には、サーバー側から見るストリームはルーム単位なのですが、そのストリームは内部的にセッション(接続)ごとの送信キューと受信キューを持っていて、各セッションはパケットの受信確認を行いながら通信する感じです。クライアント側は、自分とサーバーしかいませんから、結構どうでもいいです。

今は、そのプロトコルスタックというのか、そんなようなものを作っています。
で、まぁ、もうすでに、なにかがズレてきてるのを感じてます……あれ、セッションごとに持つデータがめちゃめちゃ増えてなーい……?とか。
うん、そう、少ないリソースで同時に扱える接続数を増やすんです、はい。

internal22-index - Linux Kernel Documents Wiki - SourceForge.JPが大まかな参考になっています。
TFTPを同時双方向通信に対応させたものと思えば、楽勝なんですけど、やるればやるほど方法がまずいことに気づいたりで、なかなか……

完成したら詳しいこと書きます。
妥協するかもしれません。