コード例 #1
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