[ Pobierz całość w formacie PDF ]
.end(); ++iPacket ){// Already in list - get out now!if( (*iPacket)->d_id == pPacket->d_id ){bExists = true;break;}if( (*iPacket)->d_id > pPacket->d_id )break;}346 if( bExists == true )delete pPacket;else{// We've gone 1 past the spot where pPacket belongs.Back up andinsert.d_packetsUnordered.insert( iPacket, pPacket );d_count++;}}cMonitor::MutexOff();}Now I could stop right here, add an instance of cQueueIn to MTUDP, and there would be almosteverything needed for reliable communications, but that's not why I went off on this tangent.There isstill no way of sending data to another computer and also no way of telling who the data came from.cHostYes, this is another new class.Don't worry, there's only four more, but they won't be mentioned for quitesome time.(I'm only telling you that to fill you with anticipation and dread in the same way Stephen Kingwould start a chapter with "three weeks before the church steeple blew up" or Hitchcock would showyou the ticking bomb hidden under a restaurant table.It's a spooky story and an education! MoreBANG! (aah!) for your buck.) The cHost class doesn't contain much yet, but it will be expanded later.class cHost : public cMonitor{DWORD d_address;unsigned short d_port;cQueueIn d_inQueue;public:cHost();virtual ~cHost();347 unsigned short ProcessIncomingReliable( char * const pBuffer, unsignedshort len, DWORD receiveTime );void SetPort( unsigned short port );bool SetAddress( const char * const pAddress );bool SetAddress( DWORD address );DWORD GetAddress(); // returns d_address.unsigned short GetPort(); // returns d_port.cQueueIn &GetInQueue(); // returns d_inQueue.};There are only two big mysteries here: SetAddress() and ProcessIncomingReliable().bool cHost::SetAddress( const char * const pAddress ){if( pAddress == NULL )return true;IN_ADDR *pAddr;HOSTENT *pHe;pHe = gethostbyname( pAddress );if( pHe == NULL )return true;pAddr = (in_addr *)pHe->h_addr_list[ 0 ];d_address = ntohl( pAddr->s_addr );return false;}The other SetAddress assumes you've already done the work, so it just sets d_address equal toaddress and returns.348As I said before, the cHost you're working with is a really simple version of the full cHost class.EvenProcessIncomingReliable(), which I'm about to show, is a simple version of the fullProcessIncomingReliable().unsigned short cHost::ProcessIncomingReliable( char * const pBuffer,unsigned short maxLen,DWORD receiveTime ){DWORD packetID;char *readPtr;unsigned short length;readPtr = pBuffer;memcpy( &packetID, readPtr, sizeof( DWORD ) );readPtr += sizeof( DWORD );memcpy( &length, readPtr, sizeof( unsigned short ) );readPtr += sizeof( unsigned short );// If this message is a packet, queue the data// to be dealt with by the application later.d_inQueue.AddPacket( packetID, (char *)readPtr, length, receiveTime );readPtr += length;// d_inQueue::d_count will be used here at a much much later date.return readPtr - pBuffer;}This might seem like overkill, but it will make the program a lot more robust and net-friendly in the nearfuture.Things are now going to start building on the layers that came before.To start with, MTUDP is going tostore a list containing all the instances of cHost, so the definition of MTUDP has to be expanded.// Used by classes that call MTUDP, rather than have MTUDP return apointer.349 typedef DWORD HOSTHANDLE;class MTUDP : public cThread{private:// purely internal shortcuts.typedef map HOSTMAP;typedef list HOSTLIST;protected:HOSTLIST d_hosts;HOSTMAP d_hostMap;HOSTHANDLE d_lastHandleID;public:HOSTHANDLE HostCreate( const char * const pAddress,unsigned short port );HOSTHANDLE HostCreate( DWORD address, unsigned short port );void HostDestroy( HOSTHANDLE hostID );unsigned short HostGetPort( HOSTHANDLE hostID );DWORD HostGetAddress( HOSTHANDLE hostID );So what exactly did I do here? Well, MTUDP returns a unique HOSTHANDLE for each host so that noone can do anything silly (like try to delete a host).It also means that because MTUDP has to be calledfor everything involving hosts, MTUDP can protect d_hostMap and d_hosts with the cThread::cMonitor.Now, it may surprise you to know that MTUDP creates hosts at times other than when some outsideclass calls HostCreate().In fact, this is a perfect time to also show you just what's going to happen tocHost::QueueIn() by revisiting MTUDP::ProcessIncomingData().void MTUDP::ProcessIncomingData( char * const pData, unsigned shortlength,DWORD address, DWORD receiveTime ){// Find the host that sent this data.350 cHost *pHost;HOSTLIST::iterator iHost;cMonitor::MutexOn();// search d_hosts to find a host with the same address.if( iHost == d_hosts.end() ){// Host not found! Must be someone new sending data to this computer.DWORD hostID;hostID = HostCreate( address, d_foreignListenPort );if( hostID == 0 )// turn mutex off and throw an error, the host creation failed.pHost = d_hostMap[ hostID ];}elsepHost = *iHost;assert( pHost != NULL );// This next part will get more complicated later.pHost->ProcessIncomingReliable( pData, length, receiveTime );}Of course, that means you now have a list of hosts
[ Pobierz całość w formacie PDF ]