当前位置: 首页 > 工具软件 > SPServer > 使用案例 >

优秀的轻量级网络开发框架spserver源码分析(一)

郗浩
2023-12-01

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.

.....未完待续

 类似资料: