Exemplo n.º 1
0
    def run(self):
        log.info('rtk thread: start')

        # threads
        self.server = ServerThread(self.listen_port)
        self.controller = ControlThread(self.control_port, self.got_command_cb)
        # station_mode 指基站的模式,本地的模式与之相反
        if self.station_mode == 'server':
            # 基站为 server, 本地为 client
            self.station = StationClientThread(self.name, self.config,
                                               self.got_data_cb,
                                               self.update_status_cb)
        else:
            # 基站为 client, 本地为 server
            self.station = StationServerThread(self.name, self.config,
                                               self.got_data_cb,
                                               self.update_status_cb)

        self.server.start()
        self.controller.start()
        self.station.start()

        # wait
        while self.running and self.server.running and self.station.running:
            time.sleep(2)

        # quit & clean up
        self.stop_thread('controller', self.controller)
        self.stop_thread('station', self.station)
        self.stop_thread('server', self.server)

        self.update_status_cb(RtkStatus.S_TERMINATED)

        log.info('rtk thread: bye')
        self.running = False
Exemplo n.º 2
0
 def wait_for_keyboard(self):
     """quit when press q or press ctrl-c, or exception from other threads"""
     try:
         while True:
             time.sleep(2)   # 减少死锁概率
             print("enter 'q' to quit, 'r' to reload, 'l' to list ports.")
             key = input().lower().strip()
             if key == 'q':
                 break
             elif key == 'r':
                 log.info('main: reload config.')
                 self.start_threads_from_config()
             elif key == 'l':
                 try:
                     print('name, station_port, dispatch_port, control_port')
                     for name, config in sorted(self.configs['entry'].items()):
                         control_port = str(config['controlPort']) if 'controlPort' in config else None
                         print('%s, %d, %d, %s'
                               % (name, config['stationPort'], config['listenPort'], control_port))
                 except Exception as e:
                     print('Error when list config: %s' % e)
     except KeyboardInterrupt:
         pass
     except (EOFError, OSError):
         # no input
         signal.signal(signal.SIGINT, self.exit_by_signal)
         signal.signal(signal.SIGTERM, self.exit_by_signal)
         while not self.is_interrupt:
             time.sleep(1)
Exemplo n.º 3
0
    def run(self):
        """线程主函数

        循环运行,接受新的客户端的连接。
        """
        log.info('station server thread: start, port: %d' % self.port)
        try:
            server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            if os.name != 'nt':
                server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
            server.bind(('0.0.0.0', self.port))
            server.listen(1)
            server.settimeout(3)    # timeout: 3s
            while self.running:
                try:
                    conn, address = server.accept()
                    conn.settimeout(3)
                    log.debug('new station connection from: %s' % str(address))
                    self.got_client(conn, str(address))
                except socket.timeout:
                    pass
                self.check_new_connections()
            # clean up
            server.close()
            self.disconnect()
            log.info('station server thread: bye')
        except Exception as e:
            log.error('station server thread error: %s' % e)
            self.running = False
        self.disconnect()
Exemplo n.º 4
0
    def run(self):
        log.info('rtk thread: start')

        # threads
        self.server = ServerThread(self.listen_port)
        self.controller = ControlThread(self.control_port, self.got_command_cb)
        # station_mode 指基站的模式,本地的模式与之相反
        if self.station_mode == 'server':
            # 基站为 server, 本地为 client
            self.station = StationClientThread(self.name, self.config,
                                               self.got_data_cb, self.update_status_cb)
        else:
            # 基站为 client, 本地为 server
            self.station = StationServerThread(self.name, self.config,
                                               self.got_data_cb, self.update_status_cb)

        self.server.start()
        self.controller.start()
        self.station.start()

        # wait
        while self.running and self.server.running and self.station.running:
            time.sleep(2)

        # quit & clean up
        self.stop_thread('controller', self.controller)
        self.stop_thread('station', self.station)
        self.stop_thread('server', self.server)

        self.update_status_cb(RtkStatus.S_TERMINATED)

        log.info('rtk thread: bye')
        self.running = False
Exemplo n.º 5
0
 def wait_for_keyboard(self):
     """quit when press q or press ctrl-c, or exception from other threads"""
     try:
         while True:
             time.sleep(2)  # 减少死锁概率
             print("enter 'q' to quit, 'r' to reload, 'l' to list ports.")
             key = input().lower().strip()
             if key == 'q':
                 break
             elif key == 'r':
                 log.info('main: reload config.')
                 configs = config_loader.load_config()
                 self.configs = configs
                 self.rtk_mgr.start_threads_from_config(self.configs)
             elif key == 'l':
                 try:
                     print(
                         'name, station_port, dispatch_port, control_port')
                     for name, config in sorted(
                             self.configs['entry'].items()):
                         print(
                             '%s, %d, %d, %s' %
                             (name, config.station_port, config.listen_port,
                              str(config.control_port)))
                 except Exception as e:
                     print('Error when list config: %s' % e)
     except KeyboardInterrupt:
         pass
     except (EOFError, OSError):
         # no input
         signal.signal(signal.SIGINT, self.exit_by_signal)
         signal.signal(signal.SIGTERM, self.exit_by_signal)
         while not self.is_interrupt:
             time.sleep(1)
Exemplo n.º 6
0
    def run(self):
        """线程主函数

        循环运行,接受新的客户端的连接。
        """
        log.info('server thread: start, port: %d' % self.port)
        try:
            server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            if os.name != 'nt':
                server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
            server.bind(('0.0.0.0', self.port))
            server.listen(100)      # 并发
            server.settimeout(1)    # timeout: 1s
            while self.running:
                # 接受连接
                try:
                    conn, address = server.accept()
                    conn.settimeout(3)
                    self.dispatcher.add_client(conn, address)
                    log.debug('new client from: %s' % str(address))
                except socket.timeout:
                    pass
                # 分发数据
                self.dispatcher.dispatch()
            server.close()
            self.dispatcher.close_all_clients()
            log.info('server thread: bye')
        except Exception as e:
            log.error('server thread error: %s' % e)
            self.running = False
Exemplo n.º 7
0
    def run(self):
        """线程主函数

        循环运行,接受新的客户端的连接。
        """
        log.info('server thread: start, port: %d' % self.port)
        try:
            server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            if os.name != 'nt':
                server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
            server.bind(('0.0.0.0', self.port))
            server.listen(100)  # 并发
            server.settimeout(1)  # timeout: 1s
            while self.running:
                # 接受连接
                try:
                    conn, address = server.accept()
                    conn.settimeout(3)
                    self.dispatcher.add_client(conn, address)
                    log.debug('new client from: %s' % str(address))
                except socket.timeout:
                    pass
                # 分发数据
                self.dispatcher.dispatch()
            server.close()
            self.dispatcher.close_all_clients()
            log.info('server thread: bye')
        except Exception as e:
            log.error('server thread error: %s' % e)
            self.running = False
Exemplo n.º 8
0
    def run(self):
        """线程主函数

        循环运行,接受到控制端口的 socket 连接(唯一),接收命令。
        """
        if self.port is None:
            return

        log.info('control thread: start, port: %d' % self.port)
        try:
            # 开始监听
            server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
            server.bind(('0.0.0.0', self.port))
            server.listen(1)
            server.settimeout(3)    # timeout: 3s
            # 循环运行,监听端口,接收命令
            while self.running:
                self.accept_client(server)
                self.receive_command()
                self.resolve_command()
                self.send_message()
            server.close()
            self.disconnect_client()
            log.info('control thread: bye')
        except Exception as e:
            log.error('control thread error: %s' % e)
            self.running = False
Exemplo n.º 9
0
    def resolve_command(self):
        """解析来自控制端口的数据

        首先寻找指令起始标记,找不到就从 buffer 头删除一个字节,再继续寻找。
        然后调用 resolve_command_from_begin() 从 buffer 的开头开始解析,直到遇到结尾标记为止。
        """
        if self.is_transparency and len(self.buffer) > 0:
            # 透传模式
            command = b'send:' + bytes(self.buffer[:])
            self.buffer.clear()
            log.info('control command: %s' % command)
            self.got_command_cb(command)

        while len(self.buffer) >= 4:
            # 解析指令
            try:
                if self.is_in_command:      # 指令从 buffer[0] 开始
                    command = self.resolve_command_from_begin()
                    if self.is_in_command:      # 没有遇到结尾,收到的指令还不完整
                        break
                    elif command is not None:   # 收到了指令
                        log.info('control command: %s' % command)
                        self.got_command_cb(command)
                        if command == b'%MODE1':
                            # 透传模式
                            self.is_transparency = True
                            break
                elif self.buffer[:4] == CMD_BEGIN:  # begin of command
                    self.is_in_command = True
                else:
                    del self.buffer[0]      # 出队一个字节
            except Exception as e:
                log.warning('control thread resolve: %s' % e)
Exemplo n.º 10
0
    def run(self):
        """线程主函数

        循环运行,接受新的客户端的连接。
        """
        log.info('station server thread: start, port: %d' % self.port)
        try:
            server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            if os.name != 'nt':
                server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
            server.bind(('0.0.0.0', self.port))
            server.listen(1)
            server.settimeout(3)  # timeout: 3s
            while self.running:
                try:
                    conn, address = server.accept()
                    conn.settimeout(3)
                    log.debug('new station connection from: %s' % str(address))
                    self.got_client(conn, str(address))
                except socket.timeout:
                    pass
                self.check_new_connections()
            # clean up
            server.close()
            self.disconnect()
            log.info('station server thread: bye')
        except Exception as e:
            log.error('station server thread error: %s' % e)
            self.running = False
        self.disconnect()
Exemplo n.º 11
0
    def check_new_connections(self):
        """检查新建的连接是否通过了握手测试"""
        new_connections = self.new_connections[:]
        time_sec = time.time()

        for i in range(0, len(new_connections)):
            connection_thread, established_time_sec = new_connections[i]
            # 逐个检查新建立的连接,判断是否握手成功、是否超时
            if connection_thread.handshake_ok:
                # 握手成功
                if self.connection_thread is not None and self.connection_thread.is_alive():
                    # stop old
                    log.info('stopping existing station connection thread.')
                    self.connection_thread.got_data_cb = lambda data: None
                    self.connection_thread.update_status_cb = lambda status: None
                    self.connection_thread.running = False  # 不用等待
                # set new connection_thread
                self.connection_thread = connection_thread
                self.connection_thread.got_data_cb = self.got_data_cb
                self.connection_thread.update_status_cb = self.update_status_cb
                self.new_connections.remove((connection_thread, established_time_sec))
            elif (time_sec - established_time_sec > handshake_timeout_second) or time_sec < established_time_sec:
                # 超时
                connection_thread.running = False   # 不用等待
                connection_thread.got_data_cb = lambda data: None
                connection_thread.update_status_cb = lambda status: None
                self.new_connections.remove((connection_thread, established_time_sec))
Exemplo n.º 12
0
    def run(self):
        """线程主函数

        循环运行,接收来自客户端的数据并丢弃,向客户端发送 data_queue 中的数据包。
        当 data_queue 过长时,丢弃旧的数据包。
        """
        log.info('station connection thread: start, %s' % self.address)
        self.update_status_cb(RtkStatus.S_CONNECTED)

        try:
            self.send_and_receive_data()
        except Exception as e:
            log.error('station connection thread error: %s' % e)
        self.update_status_cb(RtkStatus.S_DISCONNECTED)
        log.info('station connection thread: bye')
Exemplo n.º 13
0
    def run(self):
        """线程主函数

        启动定时器,用于检查心跳超时
        循环运行,接受新的客户端的连接。
        """
        log.info('http thread: start, port: %d' % self.port)

        try:
            self.server = ThreadingHTTPServer(('', self.port), RequestHandler)
            self.server.serve_forever()
        except Exception as e:
            log.error('http thread error: %s' % e)

        time.sleep(0.5)
        log.info('http thread: bye')
Exemplo n.º 14
0
    def run(self):
        """线程主函数

        启动定时器,用于检查心跳超时
        循环运行,接受新的客户端的连接。
        """
        log.info("http thread: start, port: %d" % self.port)

        try:
            self.server = ThreadingHTTPServer(("", self.port), RequestHandler)
            self.server.serve_forever()
        except Exception as e:
            log.error("http thread error: %s" % e)

        time.sleep(0.5)
        log.info("http thread: bye")
Exemplo n.º 15
0
    def main(self):
        log.info('main: start')

        # start rtk & loop
        self.rtk_mgr.start()

        # wait
        self.wait_for_keyboard()

        # quit & clean up
        self.rtk_mgr.running = False
        self.rtk_mgr.join()

        log.info('main: bye')
        log.close_all()
        base64_log.close_all()
Exemplo n.º 16
0
    def stop_thread(self, name):
        """停止某 rtk 线程,不等待

        之后需要调用 wait_for_thread

        Args:
            name (str): rtk 线程名
        """
        try:
            if name in self.rtk_threads.keys():
                rtk_thread = self.rtk_threads[name]
                if isinstance(rtk_thread, RtkGroup):
                    rtk_thread.stop()
                    log.info('main: require stop thread %d %s.' % (rtk_thread.thread_id, name))
        except Exception as e:
            log.error('main: failed to stop thread %s: %s' % (name, e))
Exemplo n.º 17
0
    def run(self):
        """线程主函数

        循环运行,接收来自客户端的数据并丢弃,向客户端发送 data_queue 中的数据包。
        当 data_queue 过长时,丢弃旧的数据包。
        """
        log.info('station connection thread: start, %s' % self.address)
        self.update_status_cb(RtkStatus.S_CONNECTED)

        try:
            self.send_and_receive_data()
        except Exception as e:
            log.error('station connection thread error: %s' % e)
        self.update_status_cb(RtkStatus.S_DISCONNECTED)
        self.running = False
        log.info('station connection thread: bye')
Exemplo n.º 18
0
    def accept_client(self, server):
        """监听控制端口

        尝试接受连接,如果有新连接,就关闭旧的连接。

        Args:
            server (socket.socket): server socket
        """
        try:
            conn, address = server.accept()
            self.disconnect_client()
            self.client = conn
            self.client.settimeout(3)
            self.is_transparency = False   # 新连接不透传
            log.info('new control client from: %s' % str(address))
        except socket.timeout:
            pass
Exemplo n.º 19
0
    def stop_thread(self, name):
        """停止某 rtk 线程,不等待

        之后需要调用 wait_for_thread

        Args:
            name (str): rtk 线程名
        """
        try:
            if name in self.rtk_threads.keys():
                rtk_thread = self.rtk_threads[name]
                if isinstance(rtk_thread, RtkGroup):
                    rtk_thread.stop()
                    log.info('main: require stop thread %d %s.' %
                             (rtk_thread.thread_id, name))
        except Exception as e:
            log.error('main: failed to stop thread %s: %s' % (name, e))
Exemplo n.º 20
0
    def update_names(names):
        """更新 rtk 服务名字列表

        Args:
            names (list[str]): 开启的 rtk 服务名
        """
        log.info("http thread: load %d name(s)" % len(names))
        # update status
        # add new name
        for name in names:
            if name not in RtkStatus.rtk_status:
                RtkStatus.rtk_status[name] = RtkStatus.S_UNKNOWN
                RtkStatus.rtk_last_rcv_time[name] = "NULL"
        # delete outdated name
        for name in RtkStatus.rtk_status.copy().keys():
            if name not in names:
                del RtkStatus.rtk_status[name]
                del RtkStatus.rtk_last_rcv_time[name]
Exemplo n.º 21
0
    def update_names(names):
        """更新 rtk 服务名字列表

        Args:
            names (list[str]): 开启的 rtk 服务名
        """
        log.info('http thread: load %d name(s)' % len(names))
        # update status
        # add new name
        for name in names:
            if name not in RtkStatus.rtk_status:
                RtkStatus.rtk_status[name] = RtkStatus.S_UNKNOWN
                RtkStatus.rtk_last_rcv_time[name] = 'NULL'
        # delete outdated name
        for name in RtkStatus.rtk_status.copy().keys():
            if name not in names:
                del RtkStatus.rtk_status[name]
                del RtkStatus.rtk_last_rcv_time[name]
Exemplo n.º 22
0
    def wait_for_thread(self, name):
        """等待某 rtk 线程完全退出

        在 stop_thread 之后调用

        Args:
            name (str): rtk 线程名
        """
        try:
            if name in self.rtk_threads.keys():
                rtk_thread = self.rtk_threads[name]
                if isinstance(rtk_thread, RtkGroup):
                    # wait
                    rtk_thread.join()
                log.info('main: thread %d %s has stopped.' % (rtk_thread.thread_id, name))
                # remove
                del self.rtk_threads[name]
        except Exception as e:
            log.error('main: error when wait for thread %s: %s' % (name, e))
Exemplo n.º 23
0
    def wait_for_thread(self, name):
        """等待某 rtk 线程完全退出

        在 stop_thread 之后调用

        Args:
            name (str): rtk 线程名
        """
        try:
            if name in self.rtk_threads.keys():
                rtk_thread = self.rtk_threads[name]
                if isinstance(rtk_thread, RtkGroup):
                    # wait
                    rtk_thread.join()
                log.info('main: thread %d %s has stopped.' %
                         (rtk_thread.thread_id, name))
                # remove
                del self.rtk_threads[name]
        except Exception as e:
            log.error('main: error when wait for thread %s: %s' % (name, e))
Exemplo n.º 24
0
    def main(self):
        log.info('main: start')

        # start rtk
        self.start_threads_from_config()

        # wait
        self.wait_for_keyboard()

        # quit & clean up
        for name in self.rtk_threads.keys():
            self.stop_thread(name)
        for name in sorted(self.rtk_threads.keys()):
            self.wait_for_thread(name)
        self.stop_and_wait_for_web_interface()

        # clear queue
        while not self.status_queue.empty():
            self.status_queue.get(block=False)

        log.info('main: bye')
        log.close_all()
Exemplo n.º 25
0
 def send_and_receive_data(self):
     """循环发送、接收数据"""
     timeout_count = 0
     while self.running:
         # 发送数据
         self.send_data_from_queue()
         # 接收数据
         try:
             data = self.client_socket.recv(BUFFER_SIZE)
             # 连接失败的处理
             if len(data) == 0:
                 raise RuntimeError('socket connection broken')
             # 收到数据后的处理
             self.parse_data(data)
             timeout_count = 0
         except socket.timeout:
             # 超时处理,超时 10 次时主动断开
             # 超时时间短是为了在需要时能快速退出
             timeout_count += 1
             if timeout_count >= 10:
                 self.running = False
                 log.info('station connection thread: timeout')
     self.disconnect()
Exemplo n.º 26
0
 def send_and_receive_data(self):
     """循环发送、接收数据"""
     timeout_count = 0
     while self.running:
         # 发送数据
         self.send_data_from_queue()
         # 接收数据
         try:
             data = self.client_socket.recv(BUFFER_SIZE)
             # 连接失败的处理
             if len(data) == 0:
                 raise RuntimeError('socket connection broken')
             # 收到数据后的处理
             self.parse_data(data)
             timeout_count = 0
         except socket.timeout:
             # 超时处理,超时 10 次时主动断开
             # 超时时间短是为了在需要时能快速退出
             timeout_count += 1
             if timeout_count >= 10:
                 self.running = False
                 log.info('station connection thread: timeout')
     self.disconnect()
Exemplo n.º 27
0
    def check_new_connections(self):
        """检查新建的连接是否通过了握手测试"""
        new_connections = self.new_connections[:]
        time_sec = time.time()

        for i in range(0, len(new_connections)):
            connection_thread, established_time_sec = new_connections[i]
            # 逐个检查新建立的连接,判断是否握手成功、是否超时
            if connection_thread.handshake_ok:
                # 握手成功
                if self.connection_thread is not None and self.connection_thread.is_alive(
                ):
                    # stop old
                    log.info('stopping existing station connection thread.')
                    self.connection_thread.got_data_cb = lambda data: None
                    self.connection_thread.update_status_cb = lambda status: None
                    self.connection_thread.running = False  # 不用等待
                # set new connection_thread
                self.connection_thread = connection_thread
                self.connection_thread.got_data_cb = self.got_data_cb
                self.connection_thread.update_status_cb = self.update_status_cb
                self.new_connections.remove(
                    (connection_thread, established_time_sec))
            elif (time_sec - established_time_sec >
                  handshake_timeout_second) or time_sec < established_time_sec:
                # 超时
                connection_thread.running = False  # 不用等待
                connection_thread.got_data_cb = lambda data: None
                connection_thread.update_status_cb = lambda status: None
                self.new_connections.remove(
                    (connection_thread, established_time_sec))

        if len(self.new_connections) == 0 and \
                self.connection_thread is not None and not self.connection_thread.running:
            # 没有新连接,旧连接有过但也断了,那么判为断开状态
            self.update_status_cb(RtkStatus.S_DISCONNECTED)
Exemplo n.º 28
0
    def run(self):
        """线程主函数

        循环运行,建立连接、接收数据,并在连接出错时重连。
        """
        log.info('station client thread: start')
        while self.running:
            try:
                # 建立连接
                conn = self.connect()
                log.info('station client thread: connected')
                # 开启数据接收线程
                self.run_receive_data_thread(conn)
            except Exception as e:
                log.error('station client thread error: %s' % e)
                time.sleep(3)
        # disconnect
        self.disconnect()
        log.info('station client thread: bye')
Exemplo n.º 29
0
    def run(self):
        """线程主函数

        循环运行,接收来自客户端的数据并丢弃,向客户端发送 data_queue 中的数据包。
        当 data_queue 过长时,丢弃旧的数据包。
        """
        log.info('sender thread %d: start, %s' % (self.sender_id, self.address))
        try:
            while self.running:
                # ignore old data
                while self.data_queue.qsize() > 10:
                    self.data_queue.get(block=False)
                # send data
                try:
                    data = self.data_queue.get(timeout=1)
                    self.client_socket.settimeout(5)
                    self.client_socket.sendall(data)
                    self.send_count += 1
                    self.data_queue.task_done()
                except queue.Empty:
                    pass
                # rcv useless data
                try:
                    self.client_socket.settimeout(0.1)
                    rcv_buf = self.client_socket.recv(256)
                    if len(rcv_buf) == 0:
                        log.info('sender thread %d has disconnected.' % self.sender_id)
                        # 退出
                        break
                except socket.timeout:
                    pass
        except Exception as e:
            log.error('sender thread %d error: %s' % (self.sender_id, e))
        self.disconnect()
        self.running = False
        log.info('sender thread %d: bye' % self.sender_id)