狐狸大叔-高效连接Socket篇(一)

狐狸大叔,这名字是我一个同事自称的,所以不要到处搜哈哈,搜不出来的 偷笑

最近几天看了狐狸大叔写的C++游戏demo框架(未完善,仅一个demo而已),我觉得太好了,所以拿出来跟大家分享一出。

框架结构:vs2008 boost mysql

本人也是菜鸟一个,但有强烈的追求看到高效的代码。如有误导各位,请痛批~


今天讲的是Socket方面的创建、连接、管理。


【总体的设计思路】
已经知道这块地最多只能住下1000个人(玩家),那就先建好1000个房子(player & socket),同时也生产好了1000接待者(每一个接待者只接一个人accept),每来一名客人就简单记录下他的地址与信息就可入住,这就是高效。

单位  单位管理者关系


单位  单位管理者关系


单位中有list<单位*>、 vector<单位*> 有定义typedef 指针管理的关系
将这些放在该类的最后面
typedef list<netSocket*> SocketList;  
typedef list<netSocket*>::iterator SocketListIter;   
typedef vector<netSocket*> SocketVector;   
typedef vector<netSocket*>::iterator SocketVectorIter;


单位管理者都有这样一个list 、vector,还有一个单位的指针数组缓存如 netSocket*  mSocket[ MAX_SOCKET ];


每当要new一个单位管理者的时候,就会创建一定数量的单位,并将放入缓存的指针数组


单位管理者有几个容器:
  netSocket*      mSocket[MAX_SOCKET];      // 缓存 
  SocketVector    mFreeSocket;              // 空闲的房子
  SocketVector    mUsedSocket;              // 已经有人住的房子


当一个玩家进入,则从mFreeSocket.begin()拿出来一个socket放入到mUserSocket.push_back(mFreeSocket.begin())中去,
mFreeSocket.earse(mFreeSocket.begin());

当一个玩家断开连接,则与上面的流程相反,当操作这些时,要适当的做锁

代码如下,怒不解讲

netSocket.h

//
//  socket.h
//  test
//
//  Created by fox on 12-11-19.
//  Copyright (c) 2012年 __MyCompanyName__. All rights reserved.
//

#ifndef netSocket_h
#define netSocket_h


#include "netIOBuffer.h"


namespace FOXSDK
{
    class netServer;
    
    
    enum SocketRecvType
    {
        FSRS_NULL = 0,
        FSRS_HEAD = 1,
        FSRS_BODY = 2,
        FSRS_COUNT = 3
    };
    
    
    struct netSocketHead
    {
        fuint16 size;
        fuint16 type;
    };
    
    
    class netSocket : public tcp::socket
    {
    public:
        
        friend class netServer;
        
        netSocket( io_service& io_service );
        
        fvoid   RecvMsg( const error_code& ec, size_t bytes_transferred );
        fvoid   SendMsg( const error_code& ec, size_t bytes_transferred );
        
        fvoid   ParkMsg( netSocketHead* head );
        fvoid   SendMsg();
        
        fint32  ReadMsg( netSocketHead** head );
        fvoid   RemoveMsg( int len );
        
        fint32  IsVaild()
        {
            return mVaild;
        }
        
        fvoid   Close()
        {
            mClose = 1;
        }
        
    protected:
        
        deadline_timer mTimer;
        
        virtual ~netSocket();
        
        fvoid   Run();
        
        virtual void    close();
        
        fvoid   Clear();
        
        //mutex   mMutex;
        
        fint32  mVaild;
        
        fvoid   ReadHead();
        fvoid   ReadBody();
        
        void    HandleWait( const error_code& error );
        
        netServer*  mServer;
        
        netIOBuffer mIBuffer;
        netIOBuffer mOBuffer;
        
        mutable_buffers_1 mHeadBuffer;
        mutable_buffers_1 mBodyBuffer;
        mutable_buffers_1 mSendBuffer1;
        
        fbyte   mRecvBuffer[ MAX_SOCKET_BUFFER ];
        fint32  mRecvStage;
        fint32  mBodyLen;
        
        fbyte   mSendBuffer[ MAX_SOCKET_BUFFER ];
        fint32  mSend;
        
        fint32  mClose;
    };
    
    typedef list<netSocket*> SocketList;
    typedef list<netSocket*>::iterator SocketListIter;
    typedef vector<netSocket*> SocketVector;
    typedef vector<netSocket*>::iterator SocketVectorIter;
    

}


#endif

netSocket.cpp

//
//  socket.cpp
//  test
//
//  Created by fox on 12-11-19.
//  Copyright (c) 2012年 __MyCompanyName__. All rights reserved.
//

#include <iostream>
#include "netsocket.h"
#include "netserver.h"
#include "logManager.h"

using namespace FOXSDK;

//mutex   netSocket::mMutex;

netSocket::netSocket( io_service& io_service ):tcp::socket ( io_service ) ,
    mHeadBuffer( buffer( mRecvBuffer , sizeof(netSocketHead) ) ),
    mBodyBuffer( buffer( mRecvBuffer + sizeof(netSocketHead) , MAX_SOCKET_BUFFER - sizeof(netSocketHead) ) ) ,
    mSendBuffer1( buffer( mSendBuffer , MAX_SOCKET_BUFFER ) ),
    mBodyLen( 0 ) , mRecvStage( FSRS_NULL ) ,
    mVaild( 0 ) ,
    mSend( 0 ) ,
    mClose( 0 ) ,
    mTimer( io_service )
{
    
    mServer = (netServer*)&io_service;
    
    mIBuffer.InitBuffer( MAX_IBUFFER_CACHE );
    mOBuffer.InitBuffer( MAX_OBUFFER_CACHE );
}

netSocket::~netSocket()
{
    
}


void    netSocket::close()
{
    tcp::socket::close();
}

fint32      netSocket::ReadMsg( netSocketHead** head )
{
    if ( !mVaild ) 
    {
        return 0;
    }
        
    if ( mIBuffer.GetLen() ) 
    {
        *head = (netSocketHead*)mIBuffer.GetBuffer();
        
        return 1;
    }
    
    return 1;
}

fvoid       netSocket::RemoveMsg( fint32 len )
{
    mIBuffer.RemoveBuffer( len );
}


fvoid       netSocket::RecvMsg( const error_code& ec, size_t bytes_transferred )
{
    mTimer.cancel();
    
    if ( ec ) 
    {
        Clear();
        mServer->SetAccept( this );
        return;
    }
    else
    {
        if ( mClose )
        {
            Clear();
            mServer->SetAccept( this );
            return;
        }
        else
        {
            switch ( mRecvStage )
            {
                case (fint32)FSRS_HEAD:
                {
                    netSocketHead* head = (netSocketHead*)mRecvBuffer;
                    mBodyLen = head->size;
                    
                    if ( mBodyLen == sizeof( netSocketHead ) )
                    {
                        mIBuffer.Write( mRecvBuffer , mBodyLen );
                        ReadHead();
                        return;
                    }
                    else
                    {
                        mRecvStage = FSRS_BODY;
                        ReadBody();
                        return;
                    }
                }
                    break;
                case (fint32)FSRS_BODY:
                {
                    mIBuffer.Write( mRecvBuffer , mBodyLen );
                    mRecvStage = FSRS_HEAD;
                    ReadHead();
                    return;
                }
                    break;
                default:
                {
                    assert( 0 );
                }
                    break;
            }
        }
        
    }
}


fvoid       netSocket::Clear()
{
    if ( !mVaild )
    {
        return;
    }
    
    mVaild = 0;
    
    mRecvStage = FSRS_NULL;
    
    mBodyLen = 0;
    
    mIBuffer.ClearBuffer();
    mOBuffer.ClearBuffer();
    
    mSend = 0;
    
    //FLOG( LOGLEVEL0 , "OnNetMsgExit %s" , this->remote_endpoint().address().to_string().c_str() );
    
    mTimer.cancel();
    
    close();
}


fvoid       netSocket::ParkMsg( netSocketHead* head )
{
    mOBuffer.Write( (fbyte*)head , head->size );
}


fvoid       netSocket::SendMsg()
{
    if ( !mSend ) 
    {
        int len = mOBuffer.ReadRemove( &mSendBuffer );
        
        if ( len )
        {
            async_write( *this , mSendBuffer1 , transfer_at_least( len ) , boost::bind( &netSocket::SendMsg , this , placeholders::error, placeholders::bytes_transferred )  ) ;
        }
        
        mSend = 1;
    }
}


fvoid       netSocket::SendMsg( const error_code& ec, size_t bytes_transferred )
{
    if ( ec )
    {
        Clear();
        mServer->SetAccept( this );
    }
    else
    {
        int len = mOBuffer.ReadRemove( &mSendBuffer );
        
        if ( len )
        {
            async_write( *this , mSendBuffer1 , transfer_at_least( len ) , boost::bind( &netSocket::SendMsg , this , placeholders::error, placeholders::bytes_transferred )  ) ;
        }
        else
        {
            mSend = 0;
        }
    }
    
}


void        netSocket::HandleWait( const error_code& error )
{
    if ( error )
    {
        return;
    }
    
    this->Clear();
    mServer->SetAccept( this );
}

fvoid       netSocket::ReadHead()
{
    async_read( *this , mHeadBuffer ,
               transfer_at_least( sizeof(netSocketHead) ) ,
               boost::bind( &netSocket::RecvMsg , this , placeholders::error, placeholders::bytes_transferred ) ) ;
    
    mTimer.expires_from_now( boost::posix_time::seconds( 120 ) );
    mTimer.async_wait( boost::bind( &netSocket::HandleWait , this , boost::asio::placeholders::error ) );
}


fvoid       netSocket::ReadBody()
{
    async_read( *this , mBodyBuffer ,
               transfer_at_least( mBodyLen - sizeof(netSocketHead) ) ,
               boost::bind( &netSocket::RecvMsg , this , placeholders::error, placeholders::bytes_transferred ) ) ;
    
    mTimer.expires_from_now( boost::posix_time::seconds( 120 ) );
    mTimer.async_wait(boost::bind( &netSocket::HandleWait , this , boost::asio::placeholders::error));
}


fvoid       netSocket::Run()
{
    mRecvStage = FSRS_HEAD;
    
    mVaild = 1;

    ReadHead();
}




netServer.h


//
//  server.h
//  test
//
//  Created by fox on 12-11-20.
//  Copyright (c) 2012年 __MyCompanyName__. All rights reserved.
//

#ifndef netServer_h
#define netServer_h



#include "netSocket.h"

namespace FOXSDK
{
    typedef fvoid(*netServerHandler)(netSocket* s);
    
    class netServer : public io_service
    {
       
        
    public:
        
        friend class netSocket;
        
        netServer();
        virtual ~netServer();
        
        fvoid   SetAccept( netSocket* socket );
        fvoid   SetAddress( const fbyte* ip , fuint16 port );
        fvoid   SetHandler( netServerHandler enter , netServerHandler exit , netServerHandler msg );
        
        fvoid   ServerRun();
        fvoid   ServerUpdate();
        
        fvoid   Start();
        fvoid   Stop();
        
        fvoid   Update();
        
        
    protected:
        
        netServerHandler OnEnter;
        netServerHandler OnExit;
        netServerHandler OnMsg;
        
        fvoid   HandleStart();
        fvoid   HandleAccept( const boost::system::error_code& error , netSocket* socket );
        
        netSocket*      GetFreeSocket();
        
        
        SocketVector    mFreeSocket;
        SocketVector    mUsedSocket;
        SocketVector    mAcceptSocket;
        
        netSocket*  mSocket[ MAX_SOCKET ];
        
        tcp::endpoint   mServerAddr;
        tcp::acceptor   mAcceptor;
        
        thread  mServiceThread;
        mutex   mClientListMutex;
        
    };

}





#endif

netServer.cpp

//
//  server.cpp
//  test
//
//  Created by fox on 12-11-20.
//  Copyright (c) 2012年 __MyCompanyName__. All rights reserved.
//

#include <iostream>
#include "netServer.h"

using namespace FOXSDK;

netServer::netServer()
:   mAcceptor( *this )
{
// 经典从这里开始
    for ( int i = 0 ; i < MAX_SOCKET ; i++ ) 
    {
        mSocket[ i ] = new netSocket( *this ); // 先创建好socket,并放入到缓存中去
        mFreeSocket.push_back( mSocket[i] ); // 加入空闲的socket
    }
}


netServer::~netServer()
{
    
}


netSocket*      netServer::GetFreeSocket()
{
    if ( mFreeSocket.empty() ) 
    {
        return NULL;
    }
    
    netSocket* socket = *mFreeSocket.begin();
    mFreeSocket.erase( mFreeSocket.begin() );
    
    return socket;
}


fvoid       netServer::SetAccept( netSocket* socket )
{
    mAcceptor.async_accept( *socket ,
                           boost::bind( &netServer::HandleAccept , this , boost::asio::placeholders::error ,
                                socket ) );
}


fvoid       netServer::SetAddress( const char* ip , unsigned short port )
{
    error_code ec;
    mServerAddr = tcp::endpoint( address::from_string( ip , ec ) , port );
    assert(!ec);
}

fvoid       netServer::SetHandler( netServerHandler enter , netServerHandler exit , netServerHandler msg )
{
    OnEnter = enter;
    OnExit = exit;
    OnMsg = msg;
}


fvoid       netServer::ServerRun()
{
    while (true)
    {
        error_code ec;
        
        try
        {
            run(ec); 
            break;
        }
        catch ( std::exception& e )
        {
            
        }
    }
}


fvoid       netServer::ServerUpdate()
{
//    while (true)
//    {
//        for ( fint32 i = 0 ; i < MAX_SOCKET ; ++i )
//        {
//            mSocket[ i ]->SendMsg();
//        }
//    }
}


fvoid       netServer::Start()
{
    thread t(boost::bind( &netServer::HandleStart , this ) );
    this_thread::yield();
    t.swap( mServiceThread );
}


fvoid       netServer::HandleStart()
{
    error_code ec;
    mAcceptor.open( mServerAddr.protocol(), ec );
    assert( !ec );
    mAcceptor.set_option(tcp::acceptor::reuse_address(true) , ec );
    assert( !ec );
    mAcceptor.bind( mServerAddr , ec ); 
    assert( !ec );
    mAcceptor.listen( socket_base::max_connections , ec ); 
    assert( !ec );
    // 这里把所有的socket都拿去accept,很聪明吧
    for ( int i = 0 ; i < MAX_SOCKET ; ++i ) 
    {
        SetAccept( mSocket[ i ] ); 
    }
    
    thread_group tg;
    for ( int i = 0; i < MAX_THREAD ; ++i )
    {
        tg.create_thread(boost::bind( &netServer::ServerRun , this ) );
    }
    
    this_thread::yield();
    tg.join_all();
    
    //ServerUpdate();
}


fvoid       netServer::Stop()
{
    
}


fvoid       netServer::Update()
{
    size_t size = mAcceptSocket.size();
    
    if ( size ) 
    {
        mutex::scoped_lock lock( mClientListMutex );
        
        size = mAcceptSocket.size();
        
        for ( int i = 0 ; i < size ; ++i )
        {
		
            SocketVectorIter iter = std::find( mUsedSocket.begin() , mUsedSocket.end() , mAcceptSocket[i] );
            if ( iter != mUsedSocket.end() ) 
            {
                (*OnExit)( *iter );
                mUsedSocket.erase( iter );
                //FLOG( LOGLEVEL0 , "OnNetMsgExit %d" , mUsedSocket.size() );
            }
            
            (*OnEnter)( mAcceptSocket[i] );
            
           
            mUsedSocket.push_back( mAcceptSocket[i] );
            //FLOG( LOGLEVEL0 , "OnNetMsgEnter %d" , mUsedSocket.size() );
        }
        
        mAcceptSocket.clear();
        
        lock.unlock();
    }
    
    size = mUsedSocket.size();
    
    for ( int i = 0 ; i < size ; ++i ) 
    {
        netSocketHead* head = NULL;
        
        int b = mUsedSocket[ i ]->ReadMsg( &head );
        
        if ( !b ) 
        {
            (*OnExit)( mUsedSocket[ i ] );
            
            mUsedSocket.erase( mUsedSocket.begin() + i );
            //FLOG( LOGLEVEL0 , "OnNetMsgExit %d" , mUsedSocket.size() );
            
            i--;
            size--;
        }
        else if ( head )
        {
            (*OnMsg)( mUsedSocket[ i ] );
            
            mUsedSocket[ i ]->RemoveMsg( head->size );
        }
    }
    
}


fvoid       netServer::HandleAccept( const boost::system::error_code& error , netSocket* socket )
{
    if ( error ) 
    {
        socket->Clear();
        SetAccept( socket );
    }
    else
    {
        // on enter
        
        mutex::scoped_lock lock( mClientListMutex );
        
//        SocketVectorIter iter = std::find( mUsedSocket.begin() , mUsedSocket.end() , socket );
//        if ( iter != mUsedSocket.end() ) 
//        {
//            OnExit();
//            mUsedSocket.erase( iter );
//        }
        
        
        mAcceptSocket.push_back( socket );
        
        socket->mClose = 0;
        socket->Run();
        
        lock.unlock();
    }
}


main.cpp


//
//  main.cpp
//  test
//
//  Created by fox on 12-11-19.
//  Copyright (c) 2012年 __MyCompanyName__. All rights reserved.
//




#include "netServer.h"
#include "dbDataBase.h"
#include "netMsgHandler.h"
#include "creatureManager.h"
using namespace FOXSDK;

fvoid RunServerExit();

#ifdef WIN32

void InitError()
{
	
}

#else

#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <execinfo.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
using namespace FOXSDK;


static void printReason(int sig, siginfo_t * info, void *secret)
{
	RunServerExit();
    
	void* array[10];
	size_t size;
#ifdef F_USE_PRINT
	char** strings;
	size_t i;
	size = backtrace( array , 10 );
	strings = backtrace_symbols( array, (int)size );
	printf( "obtained %zd stack frames.\n" , size );
	for ( i = 0; i < size; i++ )
	{
		printf( "%s\n" , strings[ i ] );
	}
	free( strings );
#else
	int fd = open( "error.log", O_CREAT | O_WRONLY );
	size = backtrace( array , 10 );
	backtrace_symbols_fd( array , (int)size , fd );
	close( fd );
#endif
	exit(0);
}

void InitError()
{
	struct sigaction myAction;
	myAction.sa_sigaction = printReason;
	sigemptyset( &myAction.sa_mask );
	myAction.sa_flags = SA_RESTART | SA_SIGINFO;
	sigaction( SIGSEGV , &myAction , NULL );
	sigaction( SIGUSR1 , &myAction , NULL );
	sigaction( SIGFPE , &myAction , NULL );
	sigaction( SIGILL , &myAction , NULL );
	sigaction( SIGBUS , &myAction , NULL );
	sigaction( SIGABRT , &myAction , NULL );
	sigaction( SIGSYS , &myAction , NULL );
	sigaction( SIGINT , &myAction , NULL );
}




#endif




netServer* gNetServer;
dbIDatabase* gDB;
fbool gIsRun = F_TRUE;
fbool gIsExit = F_TRUE;


fvoid dbexit( dbResult* result )
{
}

fvoid RunServerExit()
{
    for ( int i = 0 ; i < 25550 ; i++ )
    {
        gDB->ExecuteAsyncSQL( "SELECT * FROM new_table;" , 0 , &dbexit );
    }
    
    while( gIsExit )
    {
        fuint32 size = gDB->GetRequestSize();
        
        FLOG( LOGLEVEL4 , "db request %d." , size );
        
        if ( !size )
        {
            gIsExit = F_FALSE;
        }
    }
}



fvoid ServerInit()
{
    creatureManager::Instance();
    gCreatureManager->Init();
    
    gNetServer = new netServer(); // 这里的构造函数设计比较好
    gNetServer->SetAddress( "192.168.0.103" , 8100 );
    gNetServer->SetHandler( OnNetMsgEnter , OnNetMsgExit , OnNetMsg );
    gNetServer->Start();
    
    FLOG( LOGLEVEL4 , "server inited." );
    
    
    InitError();

    //((char *)NULL)[1] = 0;
}


fvoid ServerRun()
{
    while ( gIsRun )
    {
//        dbResult* pRessult = F_NULL;
//		while ( ( pRessult = gDB->GetAsyncResult() ) != F_NULL)
//		{
//			pRessult->callback( pRessult );
//			pRessult->Release();
//		}
        
        gNetServer->Update();
    }
}


fvoid c1( dbResult* result )
{
    dbIRecordset* pRes = result->pResult;
    dbIRecord* tempRecord = F_NULL;
    
    fulong RecordCount = pRes->CountRecord();
    
    for ( fuint32 i = 0 ; i < RecordCount ; i++ )
    {
        pRes->Move( i );
        
        tempRecord = pRes->GetRecord();
        fint32 petID = tempRecord->Field( (fuint32)0 );
        petID = 1;
    }
}


int main(int argc, const char * argv[])
{
    ServerInit(); // 今天讲这里
    
    ServerRun();
    
    RunServerExit();
    
    return 0;
}
本人也是刚学C++,很多设计模式都不懂,所以不会讲解了,看看代码了~~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值