⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mtudp.cpp

📁 <B>DirectX9.0 3D游戏编程</B>
💻 CPP
📖 第 1 页 / 共 2 页
字号:
#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 + -