📄 mtudp.cpp
字号:
#if defined( _DEBUG_VERBOSE )
OUTPUTREPORT3( " > %04d (%d/%d) 2\n", packetID, length, count );
#endif
#if defined( _DEBUG_DROPTEST ) && _DEBUG_DROPTEST > 1
if( rand() % _DEBUG_DROPTEST != _DEBUG_DROPTEST - 1 )
return;
#endif
// Send
SOCKADDR_IN remoteAddr;
unsigned short result;
memset( &remoteAddr, 0, sizeof( SOCKADDR_IN ) );
remoteAddr.sin_family = AF_INET;
remoteAddr.sin_addr.s_addr = htonl( pHost->GetAddress() );
remoteAddr.sin_port = htons( pHost->GetPort() );
// Send the data.
result = sendto( d_sendSocket,
outBuffer,
count,
0,
(SOCKADDR *)&remoteAddr,
sizeof( SOCKADDR ) );
if( result < count )
{
char errorBuffer[ 100 ];
sprintf( errorBuffer, "MTUPD::ResendData() - Sent %d of %d bytes.", result, count );
throw cNetError( errorBuffer );
}
if( result == SOCKET_ERROR )
{
char errorBuffer[ 100 ];
sprintf( errorBuffer, "MTUPD::ResendData() - sendto() error %d", WSAGetLastError() );
throw cNetError( errorBuffer );
}
}
void MTUDP::ReliableSendTo( char *pStr, unsigned short length, HOSTHANDLE hostID )
{
cHost *pHost;
cMonitor::MutexOn();
pHost = d_hostMap[ hostID ];
if( pHost == NULL )
throw cNetError( "MTUDP::ReliableSendTo() - Invalid parameters." );
char outBuffer[ MAX_UDPBUFFERSIZE ];
unsigned short count;
DWORD packetID;
count = 0;
memset( outBuffer, 0, MAX_UDPBUFFERSIZE );
// Attach the ACKs.
if( pHost->GetInQueue().GetCount() != 0 )
{
// Flag indicating this block is a set of ACKs.
outBuffer[ count ] = MTUDPMSGTYPE_ACKS;
count++;
count += pHost->AddACKMessage( &outBuffer[ count ], MAX_UDPBUFFERSIZE );
}
// Attach the message data.
packetID = pHost->GetOutQueue().GetCurrentID();
if( pStr )
{
// Flag indicating this block is a message.
outBuffer[ count ] = MTUDPMSGTYPE_RELIABLE;
count++;
memcpy( &outBuffer[ count ], &packetID, sizeof( DWORD ) );
count += sizeof( DWORD );
memcpy( &outBuffer[ count ], &length, sizeof( unsigned short ) );
count += sizeof( unsigned short );
memcpy( &outBuffer[ count ], pStr, length );
count += length;
}
// Attach the previous message, just to ensure that it gets there.
cDataPacket secondPacket;
if( pHost->GetOutQueue().GetPreviousPacket( packetID, &secondPacket ) == true )
{
// Flag indicating this block is a message.
outBuffer[ count ] = MTUDPMSGTYPE_RELIABLE;
count++;
// Append the message
memcpy( &outBuffer[ count ], &secondPacket.d_id, sizeof( DWORD ) );
count += sizeof( DWORD );
memcpy( &outBuffer[ count ], &secondPacket.d_length, sizeof( unsigned short ) );
count += sizeof( unsigned short );
memcpy( &outBuffer[ count ], secondPacket.d_data, secondPacket.d_length );
count += secondPacket.d_length;
}
count += AddClockData( &outBuffer[ count ], MAX_UDPBUFFERSIZE - count, pHost );
d_bytesTransfered += count;
#if defined( _DEBUG_VERBOSE )
OUTPUTREPORT3( " > %04d (%d/%d) 1\n", packetID, length, count );
#endif
#if defined( _DEBUG_DROPTEST ) && _DEBUG_DROPTEST > 1
if( rand() % _DEBUG_DROPTEST != _DEBUG_DROPTEST - 1 )
{
#endif
// Send
SOCKADDR_IN remoteAddr;
unsigned short result;
memset( &remoteAddr, 0, sizeof( SOCKADDR_IN ) );
remoteAddr.sin_family = AF_INET;
remoteAddr.sin_addr.s_addr = htonl( pHost->GetAddress() );
remoteAddr.sin_port = htons( pHost->GetPort() );
// Send the data.
result = sendto( d_sendSocket,
outBuffer,
count,
0,
(SOCKADDR *)&remoteAddr,
sizeof( SOCKADDR ) );
if( result < count )
{
char errorBuffer[ 100 ];
cMonitor::MutexOff();
sprintf( errorBuffer, "MTUPD::ReliableSendTo() - Sent %d of %d bytes.", result, count );
throw cNetError( errorBuffer );
}
if( result == SOCKET_ERROR )
{
char errorBuffer[ 100 ];
cMonitor::MutexOff();
sprintf( errorBuffer, "MTUPD::ReliableSendTo() - sendto() error %d", WSAGetLastError() );
throw cNetError( errorBuffer );
}
#if defined( _DEBUG_DROPTEST )
}
#endif
if( pStr )
pHost->GetOutQueue().AddPacket( pStr, length );
cMonitor::MutexOff();
}
void MTUDP::UnreliableSendTo( char *pStr, unsigned short length, HOSTHANDLE hostID )
{
cHost *pHost;
cMonitor::MutexOn();
pHost = d_hostMap[ hostID ];
if( pHost == NULL )
{
cMonitor::MutexOff();
throw cNetError( "MTUDP::UnreliableSendTo() - Invalid parameters." );
}
char outBuffer[ MAX_UDPBUFFERSIZE ];
unsigned short count;
DWORD packetID;
count = 0;
memset( outBuffer, 0, MAX_UDPBUFFERSIZE );
// Attach the ACKs.
if( pHost->GetInQueue().GetCount() != MTUDPMSGTYPE_ACKS )
{
// Flag indicating this block is a set of ACKs.
outBuffer[ count ] = 0;
count++;
count += pHost->AddACKMessage( &outBuffer[ count ], MAX_UDPBUFFERSIZE );
}
// Attach the previous message, just to ensure that it gets there.
// This is done first because of the way the unreliableInQueue works.
cDataPacket secondPacket;
packetID = pHost->GetUnreliableOutQueue().GetCurrentID();
if( pHost->GetUnreliableOutQueue().GetPreviousPacket( packetID, &secondPacket ) == true )
{
// Flag indicating this block is a message.
outBuffer[ count ] = MTUDPMSGTYPE_UNRELIABLE;
count++;
// Append the message
memcpy( &outBuffer[ count ], &secondPacket.d_id, sizeof( DWORD ) );
count += sizeof( DWORD );
memcpy( &outBuffer[ count ], &secondPacket.d_length, sizeof( unsigned short ) );
count += sizeof( unsigned short );
memcpy( &outBuffer[ count ], secondPacket.d_data, secondPacket.d_length );
count += secondPacket.d_length;
}
// Attach the message data.
if( pStr )
{
// Flag indicating this block is a message.
outBuffer[ count ] = MTUDPMSGTYPE_UNRELIABLE;
count++;
#if defined( _DEBUG_VERBOSE )
OUTPUTREPORT2( " > %04d (%d) 1\n", packetID, length );
#endif
memcpy( &outBuffer[ count ], &packetID, sizeof( DWORD ) );
count += sizeof( DWORD );
memcpy( &outBuffer[ count ], &length, sizeof( unsigned short ) );
count += sizeof( unsigned short );
memcpy( &outBuffer[ count ], pStr, length );
count += length;
}
// No clock data is added because the there is no
// response from the server so synch is impossible.
d_bytesTransfered += count;
#if defined( _DEBUG_DROPTEST ) && _DEBUG_DROPTEST > 1
if( rand() % _DEBUG_DROPTEST != _DEBUG_DROPTEST - 1 )
{
#endif
// Send
SOCKADDR_IN remoteAddr;
unsigned short result;
memset( &remoteAddr, 0, sizeof( SOCKADDR_IN ) );
remoteAddr.sin_family = AF_INET;
remoteAddr.sin_addr.s_addr = htonl( pHost->GetAddress() );
remoteAddr.sin_port = htons( pHost->GetPort() );
// Send the data.
result = sendto( d_sendSocket,
outBuffer,
count,
0,
(SOCKADDR *)&remoteAddr,
sizeof( SOCKADDR ) );
if( result < count )
{
char errorBuffer[ 100 ];
cMonitor::MutexOff();
sprintf( errorBuffer, "MTUPD::UnreliableSendTo() - Sent %d of %d bytes.", result, count );
throw cNetError( errorBuffer );
}
if( result == SOCKET_ERROR )
{
char errorBuffer[ 100 ];
cMonitor::MutexOff();
sprintf( errorBuffer, "MTUPD::UnreliableSendTo() - sendto() error %d", WSAGetLastError() );
throw cNetError( errorBuffer );
}
#if defined( _DEBUG_DROPTEST )
}
#endif
if( pStr )
pHost->GetUnreliableOutQueue().AddPacket( pStr, length );
cMonitor::MutexOff();
}
void MTUDP::ResendPackets()
{
// If there is any out queue data that has been waiting too long, send it again.
cDataPacket packet;
HOSTLIST::iterator iHost;
float ping;
cMonitor::MutexOn();
for( iHost = d_hosts.begin(); iHost != d_hosts.end(); ++iHost )
{
ping = (*iHost)->GetAverageTransPing( 70 );
// Is there any queued, ordered data that has been queued for too long?
if( (*iHost)->GetOutQueue().GetPacketForResend( (DWORD)ping, &packet ) == true )
{
// There is, so send it again!
#if defined( _DEBUG_VERBOSE )
OUTPUTREPORT0( "***********************\n" );
#endif
ResendData( &packet, *iHost );
}
}
cMonitor::MutexOff();
}
////////////////////////////////////////////////////////////////////////////////
// Improve HostCreate() by only returning a handle (probably the DWORD address)
// and using a map<> to associate handles & cHosts in the list<>.
HOSTHANDLE MTUDP::HostCreate( char *pAddress, unsigned short port )
{
if( pAddress == NULL ||
port == 0 )
return 0;
cHost *pHost;
pHost = new cHost;
if( pHost == NULL )
return 0;
if( pHost->SetAddress( pAddress ) )
{
delete pHost;
return 0;
}
pHost->SetPort( port );
cMonitor::MutexOn();
d_hosts.push_back( pHost );
d_hostMap[ pHost->GetAddress() ] = pHost;
cMonitor::MutexOff();
return pHost->GetAddress();
}
// Improve HostCreate() by only returning a handle (probably the DWORD address)
// and using a map<> to associate handles & cHosts in the list<>.
HOSTHANDLE MTUDP::HostCreate( DWORD address, unsigned short port )
{
if( address == 0 ||
port == 0 )
return 0;
cHost *pHost;
pHost = new cHost;
if( pHost == NULL )
return 0;
pHost->SetAddress( address );
pHost->SetPort( port );
cMonitor::MutexOn();
d_hosts.push_back( pHost );
d_hostMap[ pHost->GetAddress() ] = pHost;
cMonitor::MutexOff();
return pHost->GetAddress();
}
void MTUDP::HostDestroy( HOSTHANDLE hostID )
{
if( d_hosts.begin() == d_hosts.end() )
return;
cHost *pHost;
cMonitor::MutexOn();
pHost = d_hostMap[ hostID ];
if( pHost == NULL )
{
cMonitor::MutexOff();
return;
}
// Remove the host from the host map.
HOSTMAP::iterator iHost;
iHost = d_hostMap.find( hostID );
if( iHost != d_hostMap.end() )
d_hostMap.erase( iHost );
// Remove the host from the linked list.
d_hosts.remove( pHost );
// Delete the host.
delete pHost;
cMonitor::MutexOff();
}
float MTUDP::HostGetAverageLinkPing( HOSTHANDLE hostID, float percent )
{
cHost *pHost;
float val;
val = 0.0f;
cMonitor::MutexOn();
pHost = d_hostMap[ hostID ];
if( pHost != NULL )
val = pHost->GetAverageLinkPing( percent );
cMonitor::MutexOff();
return val;
}
float MTUDP::HostGetAverageTransPing( HOSTHANDLE hostID, float percent )
{
cHost *pHost;
float val;
val = 0.0f;
cMonitor::MutexOn();
pHost = d_hostMap[ hostID ];
if( pHost != NULL )
val = pHost->GetAverageTransPing( percent );
cMonitor::MutexOff();
return val;
}
bool MTUDP::HostGetIsOutEmpty( HOSTHANDLE hostID )
{
cHost *pHost;
bool val;
val = true;
cMonitor::MutexOn();
pHost = d_hostMap[ hostID ];
if( pHost != NULL )
val = pHost->GetOutQueue().IsEmpty();
cMonitor::MutexOff();
return val;
}
unsigned short MTUDP::HostGetPort( HOSTHANDLE hostID )
{
cHost *pHost;
unsigned short val;
val = 0;
cMonitor::MutexOn();
pHost = d_hostMap[ hostID ];
if( pHost != NULL )
val = pHost->GetPort();
cMonitor::MutexOff();
return val;
}
DWORD MTUDP::HostGetAddress( HOSTHANDLE hostID )
{
cHost *pHost;
DWORD val;
val = 0;
cMonitor::MutexOn();
pHost = d_hostMap[ hostID ];
if( pHost != NULL )
val = hostID;
cMonitor::MutexOff();
return val;
}
////////////////////////////////////////////////////////////////////////////////
// Add the net-wide clock synch info.
// Thread safe because it is called from inside ProcessIncomingData()
unsigned short MTUDP::AddClockData( char *pData, unsigned short maxLen, cHost *pHost )
{
DWORD time;
char *ptr;
ptr = pData;
if( d_bIsServerOn == true )
{
if( pHost->WasClockTimeSet() == true )
{
if( maxLen < sizeof( DWORD ) * 2 + 1 )
throw cNetError( "MTUDP::AddClockData() - Insufficient buffer space." );
*ptr = MTUDPMSGTYPE_CLOCK;
ptr++;
time = pHost->GetLastClockTime();
memcpy( ptr, &time, sizeof( DWORD ) );
ptr += sizeof( DWORD );
time = d_clock.GetTime();
memcpy( ptr, &time, sizeof( DWORD ) );
ptr += sizeof( DWORD );
}
}
else if( d_bIsClientOn == true )
{
if( maxLen < sizeof( DWORD ) + 1 )
throw cNetError( "MTUDP::AddClockData() - Insufficient buffer space." );
*ptr = MTUDPMSGTYPE_CLOCK;
ptr++;
time = GetTickCount();
memcpy( ptr, &time, sizeof( DWORD ) );
ptr += sizeof( DWORD );
}
return ptr - pData;
}
unsigned short MTUDP::ProcessIncomingClockData( char *pData, unsigned short len, cHost *pHost, DWORD receiveTime )
{
// Process clock time.
DWORD oldTime;
char *ptr;
ptr = pData;
if( d_bIsServerOn == true )
{
memcpy( &oldTime, ptr, sizeof( DWORD ) );
ptr += sizeof( DWORD );
pHost->SetLastClockTime( oldTime );
#if defined( _DEBUG_CLOCK )
OUTPUTREPORT1( "clock: host sends %d\n", oldTime );
#endif
}
else if( d_bIsClientOn == true )
{
DWORD serverTime;
memcpy( &oldTime, ptr, sizeof( DWORD ) );
ptr += sizeof( DWORD );
memcpy( &serverTime, ptr, sizeof( DWORD ) );
ptr += sizeof( DWORD );
d_clock.Synchronize( serverTime, oldTime, receiveTime, pHost->GetAverageLinkPing( 30 ) );
#if defined( _DEBUG_CLOCK )
OUTPUTREPORT2( "clock: server sends %d, %d\n", oldTime, serverTime );
#endif
}
return ptr - pData;
}
////////////////////////////////////////////////////////////////////////////////
// Counts the number of bits required to hold a given value
unsigned short MTUDP::CountBits( DWORD value )
{
int count;
count = 0;
while( value )
{
value >>= 1;
count++;
}
return count;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -