处理套接字程序

时间:2015-08-11 09:27:28

标签: python sockets memory-leaks

我在python中的套接字编程和线程方面经验不足。我正在研究将GPS位置数据发送到服务器的设备。设备可以在长连接模式下工作,这意味着一旦设备连接到服务器,它就会使连接保持活动状态(很多)。

当我检查Ubuntu系统资源使用情况(使用top或htop)时,我看到我的进程增加了虚拟和常驻内存使用量。进程从~55 MB虚拟内存和~12 MB驻留内存开始。 3天后,虚拟内存增加到~14 GB,而Resident内存使用量约为90 MB。

这个统计数据对我来说似乎不正常,虚拟和常驻内存使用率从未下降,这让我怀疑内存泄漏。由于我对线程编程和套接字编程不是很有经验,所以我很难检查可能存在的问题。

我的代码如下:

_log = Logger("Orion_EasyTrac").create_logger()

server = Server("", 9985, logger=_log)
server.start()

Server上课

class Server(object):
    def __init__(self, host, sock_port, buffsize=8192, logger=None):
        self.hostname = host
        self.sock_port = sock_port
        self.buffsize = buffsize
        self.socket = None
        self.log = logger or _log

    def start(self):
        self.log.info("Listening: {prt}".format(prt=self.sock_port))
        self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        self.socket.bind((self.hostname, self.sock_port))
        self.socket.listen(5)

        while True:
            conn, address = self.socket.accept()
            thread.start_new_thread(EasyTrackProHandler(conn=conn, buff_size=self.buffsize, log=self.log).handle_data, ())

EasyTrackPro

的基本部分
class EasyTrackPro(object):
    def __init__(self, conn, buff_size, log):
        self.conn = conn
        self.buff_size = buff_size
        self.log = log
        self.db_conn = None                         
        self.cursor = None                          
        self.db_connector = None                    
        self.ack_parameter = None
        self.device_id = None
        self.user_id = None
        self.beaconID = None
        self.error_count = 0

    ...
    ...

    def handle_data(self):
        while True:
            try:
                _veri = self.conn.recv(self.buff_size)
                if not _veri:
                    # We do not recieve any data...
                    raise NoIncomingDataException()
            except NoIncomingDataException:
                # No need to log anything in here...
                break
            except Exception as h_e:
                self.log.exception(self._log_msg("Socket exception {h_e}".format(h_e=h_e)))
                break
            else:
                self.control_data(_veri)
        self.conn.close()

self.control_data(_veri)是完成这项工作的一部分,但由于它很长很复杂,分享那部分似乎不合逻辑。

Logger是一个使用python logging模块并记录到文本文件的类。

我的猜测是,垃圾收集器无法收集旧对象,或者由于设备使用长连接,服务器端永远不会关闭打开的套接字。但不确定其中任何一个。

这种内存泄漏可能是什么问题?

更新:我的记录器类

class Logger:
    def __init__(self, log_name, level='INFO', log_dir='logs', log_format=None, handler=None):
        """
        log_name:   log file name
        level:      log levels: CRITICAL, ERROR, WARNING, INFO, DEBUG
        log_dir:    log folder. default <file_path>/logs/
        log_format: logging format
        handler:    TODO (incomplete)
        """
        self.__log_name = log_name
        self.__formatter = None
        self.__handler = handler
        self.__level = None
        self.__log_format = u"%(asctime)s %(levelname)s %(name)s %(process)d %(threadName)s %(module)s: " \
                            u"%(lineno)d %(funcName)s(): %(message)s\r\n"
        self.loger = None

        self.__configure_level(level.upper())
        self.__configure_format(log_format)
        self.__configure_handler(log_dir)

    def __configure_level(self, level):
        if level and (level not in ['CRITICAL', 'ERROR', 'WARNING', 'INFO', 'DEBUG']):
            raise Exception(u"{lvl} is not a valid log level".format(lvl=level))
        self.__level = level or 'INFO'

    def __configure_format(self, log_format):
        if log_format:
            self.__log_format = log_format
        self.formatter = logging.Formatter(self.__log_format)

    def __configure_handler(self, log_dir):
        _dir = '{b_dr}/{l_dr}'.format(b_dr=os.path.dirname(os.path.abspath(__file__)), l_dr=log_dir)
        if not os.path.exists(_dir):
            os.mkdir(_dir)
        _filename = "{dr}/{lnf}.log".format(dr=_dir, lnf=self.__log_name)
        self.handler = handlers.WatchedFileHandler(_filename, mode="a", encoding="utf-8")
        self.handler.setFormatter(self.formatter)

    def create_logger(self):
        _loger = logging.getLogger(self.__log_name)
        _loger.setLevel(getattr(logging, self.__level))
        _loger.addHandler(self.handler)
        self.loger = _loger
        return _loger

0 个答案:

没有答案