2021SC@SDUSC
os-sim/frameworked源码分析之listener.py
一、引用库
#
# GLOBAL IMPORTS
#
import re
import socket
import SocketServer
import sys
import threading
import json
from time import sleep
全局引用有:
1、re(Regular Expression):正则表达式
2、socket:套接字,socket模块是针对 服务器端 和 客户端Socket 进行【打开】【读写】【关闭】
3、socketserver
4、sys:该模块提供对解释器使用或维护的一些变量的访问,以及与解释器强烈交互的函数
5、threading:多线程编程
6、JSON (JavaScript Object Notation) 是一种轻量级的数据交换格式。Python3 中可以使用 json 模块来对 JSON 数据进行编解码,它主要提供了四个方法: dumps、dump、loads、load。
7、time:time库是python中处理时间的标准库
#
# LOCAL IMPORTS
#
import Action
from DoControl import ControlManager
from DoASEC import ASECHandler
from DoWS import WSHandler
from DoNagios import NagiosManager
from BackupManager import BackupRestoreManager
from Logger import Logger
from OssimConf import OssimConf
from OssimDB import OssimDB
from DBConstantNames import *
本地引用:
来自同文件夹(frameworked/ossimframework)下的文件,后面具体分析。
二、class FrameworkBaseRequestHandler(SocketServer.StreamRequestHandler)
1、一个静态方法_check_sensor_ip
:
检查请求是否来自传感器。
Args:addr:具有ip地址和请求端口的元组
返回:如果地址对应于传感器,则为True,否则为false。
@staticmethod
def __check_sensor_ip(addr):
"""
Checks if the request is coming from a sensor.
Args:
addr: tuple with ip address and port of the request
Returns:
True if address corresponds to a sensor, false otherwise.
"""
try:
conf = OssimConf()
myDB = OssimDB(conf[VAR_DB_HOST],
conf[VAR_DB_SCHEMA],
conf[VAR_DB_USER],
conf[VAR_DB_PASSWORD])
myDB_connected = myDB.connect()
except Exception, msg:
# Cannot connect to database, return false.
logger.warning("Cannot find registered sensors: %s" % str(msg))
return False
query = 'select inet6_ntoa(sensor.ip) as ip from sensor, system where sensor.id=system.sensor_id;'
result = myDB.exec_query(query)
# Python doesn't support assignments in while statements...
for r in result:
if r['ip'] == addr:
return True
else:
return False
其中OssimConf与OssimDB是来自本地文件的类,提供了初始化方法:
def __init__ (self, config_file=DEFAULT_CONFIG_FILE):
self._conf = {}
# get config only from ossim.conf file
# (for example, when you only need database access)
self._get_conf(config_file)
query返回了"选择inet6_ntoa(sensor.ip)作为传感器的ip,系统中sensor.id=system.sensor_id;"
然后调用OssimDB的exec_query
方法传递query消息。
2、handle方法
检查命令是否可用,这里命令可能来自传感器或本地。
if self.__check_sensor_ip(self.client_address[0]) or self.client_address[0] == '127.0.0.1':
if command == "ping":
response = "pong\n"
elif command == "control":
# spawn our control timer
if controlmanager is None:
controlmanager = ControlManager(OssimConf())
response = controlmanager.process(self, command, line)
elif self.client_address[0] == '127.0.0.1':
# Only control messages coming from localhost.
if command == "nagios":
if self.__nagiosmanager is None:
self.__nagiosmanager = NagiosManager(OssimConf())
response = self.__nagiosmanager.process(line)
elif command == "add_asset" or command == "remove_asset" or command == "refresh_asset_list":
linebk = ""
if controlmanager is None:
controlmanager = ControlManager(OssimConf())
linebk = "action=\"refresh_asset_list\"\n"
response = controlmanager.process(self, command, linebk)
............................
这里我复制部分判断代码,每个判断部分逻辑结构类似。
判断命令类型,给出response
,response
是格式化输出字符串。(应该是ossim通过给出的反馈)
# return the response as appropriate
if len(response) > 0:
self.wfile.write(response)
line = ""
- 如果命令是Ping,response=“ping/n”
- 如果命令是control,response调用
controlmanager.process
,目的是生成控制计时器。 - 如果是来自本地的消息:对命令判断,任何再调用
controlmanager.process
。
3、一些set/get方法
对一些地址,传感器Id等进行获取和设置。
三、class FrameworkBaseServer(SocketServer.ThreadingTCPServer)
class FrameworkBaseServer(SocketServer.ThreadingTCPServer):
allow_reuse_address = True
# Uncomment for Non SSL
def __init__(self, server_address, handler_class=FrameworkBaseRequestHandler):
SocketServer.ThreadingTCPServer.__init__(self, server_address, handler_class)
return
def serve_forever(self):
while True:
try:
self.handle_request()
except Exception, e:
raise e
logger.error("Error handling request: %s" % str(e))
break
return
TCPServer
是接收到请求后执行handle方法,如果前一个的handle没有结束,那么其他的请求将不会受理,新的客户端也无法加入。
而ThreadingTCPServer
和ForkingTCPServer则允许前一连接的handle未结束也可受理新的请求和连接新的客户端,区别在于前者用建立新线程的方法运行handle,后者用新进程的方法运行handle。
了解ThreadingTCPServer
可参考这篇博客:https://www.cnblogs.com/koushuige/p/7929412.html
四、class listener
监听事件,返回内容和地址,同时捕获异常。
class Listener(threading.Thread):
def __init__(self):
self.__conf = OssimConf()
self.__server = None
threading.Thread.__init__(self)
def run(self):
try:
# Uncomment for SSL
# certfile='/var/ossim/ssl/local/cert_local.pem'
# keyfile='/var/ossim/ssl/local/key_local.pem'
serverAddress = ("0.0.0.0", int(self.__conf[VAR_FRAMEWORK_PORT]))
logger.info("Listen on: %s:%s" % serverAddress)
sleep(3)
# Uncomment for Non SSL
self.__server = FrameworkBaseServer(serverAddress, FrameworkBaseRequestHandler)
# Uncomment for SSL
# self.__server = FrameworkBaseServer(serverAddress, FrameworkBaseRequestHandler, certfile=certfile, keyfile=keyfile, conf=OssimConf())
self.__server.serve_forever()
except socket.error, e:
logger.critical("Something wrong happend while binding the socket. %s" % str(e))
sys.exit(-1)
except Exception, e:
logger.error("ERROR: %s" % str(e))
sys.exit(-1)