struct ProxyConn { CoopRunnable<CoopSocketReader, ProxyConn> clientRead; CoopRunnable<CoopSocketWriter, ProxyConn> clientWrite; CoopRunnable<CoopSocketReader, ProxyConn> serverRead; CoopRunnable<CoopSocketWriter, ProxyConn> serverWrite; CoopRunnable<CoopSleeper, ProxyConn> timeout; CoopBuffer dataToServer; CoopBuffer dataToClient; ProxyConn(int clientSock, sockaddr *, socklen_t); ~ProxyConn() { close(clientRead.sock); close(serverRead.sock); } ProxyConn *Init(); void ResetTimeout() { timeout.SetTimeout(10); } void OnTimeout(CoopSleeper *) { delete this; } void OnServerConnect(CoopSocketWriter *) { ResetTimeout(); clientRead.isActive = true; serverRead.isActive = true; serverWrite.func = &ProxyConn::OnServerWrite; } void OnClientRead(CoopSocketReader *) { ResetTimeout(); if (! CoopTransfer::OnRead(&clientRead, &serverWrite, dataToServer)) delete this; } void OnServerWrite(CoopSocketWriter *) { ResetTimeout(); if (! CoopTransfer::OnWrite(&clientRead, &serverWrite, dataToServer)) delete this; } void OnServerRead(CoopSocketReader *) { ResetTimeout(); if (! CoopTransfer::OnRead(&serverRead, &clientWrite, dataToClient)) delete this; } void OnClientWrite(CoopSocketWriter *) { ResetTimeout(); if (! CoopTransfer::OnWrite(&serverRead, &clientWrite, dataToClient)) delete this; } }; ProxyConn::ProxyConn(int clientSock, sockaddr *, socklen_t) : clientRead(this, &ProxyConn::OnClientRead), clientWrite(this, &ProxyConn::OnClientWrite), serverRead(this, &ProxyConn::OnServerRead), serverWrite(this, &ProxyConn::OnServerConnect), timeout(this, &ProxyConn::OnTimeout) { clientRead.sock = clientWrite.sock = clientSock; serverRead.sock = serverWrite.sock = ::socket(AF_INET, SOCK_STREAM, 0); assert(serverRead.sock != -1); }

もちろん現代的なサーバプログラムでは、CPU のマルチコア化を背景にマルチスレッドのプログラムを書くことが多いです。しかし、例えばチャットサーバのようにコネクション間の情報交換が多い場合は、今でもこのようなシングルスレッドによるステートマシンによる実装の方が現実的な場合も多いでしょう。

また、上の ProxyConn クラスでは、OnClientRead と OnServerWrite、OnServerRead と OnClientWrite という２つのメンバ関数の組み合わせで、双方向のストリームを実装していますが、このようなフレームワークではストリームの本数を増やすことも容易です。たとえばｘ本のサーバ接続を重畳して１本のクライアントに接続する、といったことも簡単にできます。

そして、そのようなモデルの高速なサーバを容易に、かつ型安全に書ける、という点において、C++ は優れた言語であると思います。

4月24日追記: 上記コードは簡潔さを重視して再実装したので、最適化という観点からはまだまだできることがあります。思いつく範囲で 高速なサーバの書き方補遺 - id:kazuhookuのメモ置き場 に箇条書きにしておいたので、あわせてご覧ください。