예제 #1
0
 def RecvSync(self, timeout):
     '''The receiving end of Sync().
     Return value:
     0 on success and -1 on failure.
     '''
     end_time = time.time() + timeout
     reply = TPMessage()
     reply.method = TPMessage.METHOD_SYNC
     while time.time() < end_time:
         try:
             (ready, _, _) = select.select([self], [], [],
                 max(0, end_time - time.time()))
             if ready == []:
                 continue
             msg = self.ReadEvent()
             recv_time = time.time()
             reply.timestamp = int(recv_time * 1000)
             if msg.event_type != EventType.HANDSHAKE:
                 break
             if msg.method != TPMessage.METHOD_SYNC:
                 break
             reply.ack = msg.seq
             (_, ready, _) = select.select([], [self], [],
                     max(0, end_time - time.time()))
             if ready == []:
                 continue
             self.WriteEvent(reply)
             logger.debug('Sent timestamp {0}.'.format(reply.timestamp))
         except Exception as e:
             logger.exception(e)
             return -1
     return 0
 def test_ReadAndWriteEvent_Handshake_2(self):
     evt = TPMessage()
     evt.method = 4
     evt.timestamp = 40000000
     self.template_ReadAndWriteEvent(evt)
예제 #3
0
 def test_SerializeAndDeserialize_2(self):
     msg = TPMessage()
     msg.timestamp = 10
     self.template_SerializeAndDeserialize(msg)
예제 #4
0
    def Sync(self, timeout, sync_rate):
        '''Measure the latency and clock-difference to the peer.
        This UDPSocket must be 'connected' to a peer.
        self.latency will be set to half the average round-trip-time in msec.
        self.delta will be set to the estimated clock-difference in msec.

        We use Cristian's algorithm to estimate the clock difference.
        We assume clock drift is negligible over the course of the game.
        Arguments:
        timeout   -- The time allocated to this method.
        sync_rate -- The maximum number of messages to send per second.
        Return value: 0 on success and -1 on error.
        '''
        assert timeout >= 0
        assert sync_rate > 0 
        initial_seq = self.sock.seq
        time_between_send = 1.0 / sync_rate
        last_send = 0.0
        end_time = time.time() + timeout
        n = 0
        average_rtt = 0
        min_rtt = 1000000
        while time.time() < end_time:
            if time.time() - last_send < time_between_send:
                continue
            # Expect up to time_between_send * sync_rate + 1 messages
            assert self.sock.seq - initial_seq <= timeout * sync_rate
            expected_ack = self.sock.seq
            msg = TPMessage()
            msg.method = TPMessage.METHOD_SYNC
            msg.seq = self.sock.seq
            try:
                (_, ready, _) = select.select([], [self], [], 
                        max(0, end_time - time.time()))
                if ready == []:
                    continue
                logger.debug('Sending seq {0}.'.format(msg.seq))
                start_trip = time.time() 
                last_send = start_trip
                self.WriteEvent(msg)
                seq_end_time = start_trip + time_between_send
                # Wait and read until we find the expected response or timeout.
                while True:
                    reply = None
                    remaining = seq_end_time - time.time()
                    (ready, _, _) = select.select([self], [], [], remaining)
                    if ready == []:
                        break
                    reply = self.ReadEvent()
                    end_trip = time.time()
                    if reply.event_type != EventType.HANDSHAKE:
                        continue
                    if reply.method != TPMessage.METHOD_SYNC:
                        continue
                    if reply.ack != expected_ack:
                        logger.info('Reply was out of order')
                        continue
                    break
                if reply == None:
                    continue
                logger.info('Received sync response.')
                rtt = int((end_trip - start_trip) * 1000)
                delta = reply.timestamp - int(start_trip * 1000)
                if rtt < min_rtt:
                    min_rtt = rtt
                    self.delta = int(delta - (min_rtt // 2))
                average_rtt = (average_rtt * n + rtt) / (n + 1)
                logger.info(\
                    'timestamp={0}, start={1}, delta={2}, end={3}'.format( \
                        reply.timestamp, start_trip,
                        delta, end_trip))
                n += 1
            except Exception as e:
                logger.exception(e)
                return -1
        self.latency = int(average_rtt // 2)
        if n == 0:
            logger.info('Failed to get any sync data')
            return -1
        return 0
예제 #5
0
 def Handshake(self, svr, resend, timeout):
     '''Perform a handshake with the server. This must be done prior to 
     starting the game. This method sets self.conf to the game configuration 
     provided by the server.
     self.conf.start_time is sent separately and set when the start of game
     is confirmed.
     Argument:
     svr     -- A UDPEventSocket connected to the server.
     resend  -- Number of duplicate messages to send.
     timeout -- Timeout for the handshake.
     Return value:
     True if the handshake succeeded and False otherwise.
     '''
     start_time = time.time()
     end_time = start_time + timeout
     logger.info('Waiting for server to initiate handshake.')
     did_receive_invitation = False
     while time.time() < end_time:
         try:
             (ready, _, _) = select.select([svr], [], [], 
                     end_time - time.time())
             if ready == []:
                 continue
             msg = svr.ReadEvent()
         except Exception as e:
             logger.exception(e)
             continue
         if msg.event_type != EventType.CONFIGURE:
             continue
         self.conf = msg
         did_receive_invitation = True
         break
     if not did_receive_invitation:
         logger.info('Handshake timed out. Failing.')
         return False
     logger.info('Sending confirmation.')
     reply = TPMessage()
     reply.method = TPMessage.METHOD_CONFIRM
     try:
         status = svr.WriteEvent(reply, 0.5, resend)
     except Exception as e:
         logger.exception(e)
         return False           
     if status != 0:
         logger.error('Failed to send confirmation.')
         return False
     logger.info('Waiting for start of game.')
     did_receive_start = False
     end_time = time.time() + 0.5
     while time.time() < end_time:
         try:
             (ready, _, _) = select.select([svr], [], [], 
                     end_time - time.time())
             if ready == []:
                 continue
             msg = svr.ReadEvent()
         except Exception as e:
             logger.exception(e)
             continue
         if msg.event_type != EventType.HANDSHAKE:
             logger.debug('Incorrect message type received.')
             continue
         if msg.method == TPMessage.METHOD_STARTGAME:
             did_receive_start = True
             self.conf.start_time = msg.timestamp
             break
     if not did_receive_start:
         logger.info('Handshake timed out.')
         return False
     logger.info('Handshake succeeded.')
     return True