サーバー実装を見る。
class Server: public nine::TransceiverHandler
{
public:
Server();
virtual ~Server();
void init(int nTransceivers);
bool listenLater(uint16_t port);
void run();
public:
virtual void onAcceptorListen(int id, bool succeed);
virtual void onAcceptorAccept(int id, int cid);
virtual void onAcceptorClose(int id);
virtual void onAcceptorError(int id);
inline virtual void onCommunicatorConnect(int id, bool succeed);
inline virtual void onCommunicatorAccept(int id, int cid);
inline virtual void onCommunicatorClose(int id);
inline virtual void onCommunicatorError(int id);
inline virtual void onCommunicatorReceiveTimeout(int id);
inline virtual void onCommunicatorSendTimeout(int id);
private:
bool m_listen;
nine::Transceiver* m_pTransceiver;
};
Client と同様である。
これもおおよそは Client と同様である。
一つ大きな違いは、接続を待ち受けるために Transceiver::Create() の Acceptor 数を 1 に指定していることである。
void Server::init(int n)
{
m_pTransceiver = nine::Transceiver::Create(1, n);
m_pTransceiver->setHandler(this);
m_listen = false;
}
Client は能動的に接続を行うので、Communicator 系のハンドラを使っていた。 対して Server は受動的に接続を待つので、Acceptor 系のハンドラを使う。
void Server::onAcceptorListen(int id, bool succeed)
{
m_listen = succeed;
printf("listen: %s(%d)\n", (succeed)? "succeed": "failed", id);
}
void Server::onCommunicatorAccept(int id, int cid)
{
printf("accept: id=%d\n", cid);
nine::Communicator* p = m_pTransceiver->getCommunicator(cid);
if (p) {
// p->dump(true);
}
}
接続確立時に onCommunicatorAccept を使っているが、これは onAcceptorAccept を使ってもいい(両方呼ばれる)。
これも Client と同じく、無限ループで呼んでいる。
void Server::run()
{
int n = m_pTransceiver->getCommunicatorSize();
while (true) {
m_pTransceiver->turn();
...
nine::msleep(1);
}
}
int n = m_pTransceiver->getCommunicatorSize();
for (int i=0; i<n; ++i) {
nine::Communicator* pComm = m_pTransceiver->getCommunicator(i);
if (pComm) {
n は接続可能数なので、現時点での接続数とは異なる。 未接続の場合は getCommunicator() は NULL を返すので、確認する。
nine::Buffer* pBuf = pComm->getReceiveBuffer();
int8_t ch;
while (! pBuf->isEmpty()) {
pBuf->readInt8(&ch);
printf("%c", reinterpret_cast< char* >(ch));
}
fflush(0);
使用しているバッファ操作は isEmpty() と readInt8() の二つである。
isEmpty() は読み込み可能なデータがあるかどうかを真偽値で返す。 while 文によって、データが空になるまで繰り返すようになっている。
実際にデータを読むのは readInt8() である。 これは名のとおり、符号付き8bit整数を読み込む。つまり 1byte 読んでいる。
1byte ずつ読むたびに while を回しているのは効率が悪い。 実アプリケーションでは、readableSize() と readArray() や getReadBuffers() を使って一気に処理すべきであろう。
Server サンプルではデータ受信は実装していないが、もちろんサーバーでもデータの受信は可能である。 実装方法は Client サンプルを参照されたい。