1。架構介紹
http://iunknown.javaeye.com/blog/59804
2。源碼分析
下文源碼分析基於最新源碼0.9.5,http://code.google.com/p/spserver/downloads/list
3。主程式
SP_Server的調用鏈條是runForever()->eventLoop()->start()
start()中有如下方法
acceptArg.mEventArg = &eventArg;
acceptArg.mHandlerFactory = mHandlerFactory;
acceptArg.mIOChannelFactory = mIOChannelFactory;
acceptArg.mReqQueueSize = mReqQueueSize;
acceptArg.mMaxConnections = mMaxConnections;
acceptArg.mRefusedMsg = mRefusedMsg;
struct event evAccept;
event_set( &evAccept, listenFD, EV_READ|EV_PERSIST,
SP_EventCallback::onAccept, &acceptArg );
event_base_set( eventArg.getEventBase(), &evAccept );
event_add( &evAccept, NULL );
結合libevent我們可以看出,這裡是將伺服器的socket(listenFD)和EV_READ事件註冊到libevent當中
當有用戶端連入時,去找SP_EventCallback::onAccept去處理
轉入到SP_EventCallback::onAccept 當中,可以注意到如下關鍵代碼
void SP_EventCallback :: onAccept( int fd, short events, void * arg )
{
int clientFD;
struct sockaddr_in addr;
socklen_t addrLen = sizeof( addr );
SP_AcceptArg_t * acceptArg = (SP_AcceptArg_t*)arg;
SP_EventArg * eventArg = acceptArg->mEventArg;
clientFD = accept( fd, (struct sockaddr *)&addr, &addrLen );
if( -1 == clientFD ) {
sp_syslog( LOG_WARNING, "accept failed" );
return;
}
if( SP_IOUtils::setNonblock( clientFD ) < 0 ) {
sp_syslog( LOG_WARNING, "failed to set client socket non-blocking" );
}
SP_Sid_t sid;
sid.mKey = eventArg->getSessionManager()->allocKey( &sid.mSeq );
assert( sid.mKey > 0 );
SP_Session * session = new SP_Session( sid );
char strip[ 32 ] = { 0 };
SP_IOUtils::inetNtoa( &( addr.sin_addr ), strip, sizeof( strip ) );
session->getRequest()->setClientIP( strip );
session->getRequest()->setClientPort( ntohs( addr.sin_port ) );
if( 0 == getsockname( clientFD, (struct sockaddr*)&addr, &addrLen ) ) {
SP_IOUtils::inetNtoa( &( addr.sin_addr ), strip, sizeof( strip ) );
session->getRequest()->setServerIP( strip );
}
if( NULL != session ) {
eventArg->getSessionManager()->put( sid.mKey, sid.mSeq, session );
session->setHandler( acceptArg->mHandlerFactory->create() );
session->setIOChannel( acceptArg->mIOChannelFactory->create() );
session->setArg( eventArg );
event_set( session->getReadEvent(), clientFD, EV_READ, onRead, session );
event_set( session->getWriteEvent(), clientFD, EV_WRITE, onWrite, session );
if( eventArg->getSessionManager()->getCount() > acceptArg->mMaxConnections
|| eventArg->getInputResultQueue()->getLength() >= acceptArg->mReqQueueSize ) {
sp_syslog( LOG_WARNING, "System busy, session.count %d [%d], queue.length %d [%d]",
eventArg->getSessionManager()->getCount(), acceptArg->mMaxConnections,
eventArg->getInputResultQueue()->getLength(), acceptArg->mReqQueueSize );
SP_Message * msg = new SP_Message();
msg->getMsg()->append( acceptArg->mRefusedMsg );
msg->getMsg()->append( "/r/n" );
session->getOutList()->append( msg );
session->setStatus( SP_Session::eExit );
addEvent( session, EV_WRITE, clientFD );
} else {
SP_EventHelper::doStart( session );
}
} else {
eventArg->getSessionManager()->remove( sid.mKey, sid.mSeq );
sp_close( clientFD );
sp_syslog( LOG_WARNING, "Out of memory, cannot allocate session object!" );
}
}
有上述分析,可以看到accept收到了clientFD,然後建立session,由event_set對clientFD和session進行封裝,當clientFD產生EV_READ(有資料傳入伺服器)時調用onRead,當clientFD產生EV_WRITE(資料可以發送)調用onWrite.
.....未完待續