process.py 6.28 KB
# -*- coding: UTF-8 -*-

# -------------------------------------------------
#    请不要随意修改文件中的代码
# -------------------------------------------------


import sys
import time
import threading
import socket
import json
import datetime

import php_python

REQUEST_MIN_LEN = 10  # 合法的request消息包最小长度
TIMEOUT = 180  # socket处理时间180秒

pc_dict = {}  # 预编译字典,key:调用模块、函数、参数字符串,值是编译对象
global_env = {}  # global环境变量


def index(byte_str, c, pos=0):
    """
    查找c字符在bytes中的位置(从0开始),找不到返回-1
    pos: 查找起始位置
    """
    for i in range(len(byte_str)):
        if i <= pos:
            continue
        if byte_str[i] == c:
            return i
    else:
        return -1


def parse_php_req(p):
    """
    解析PHP请求消息
    返回:元组(模块名,函数名,入参list)
    """

    str_p = bytes.decode(p)
    params = json.loads(str_p)

    module_func = params[0]  # 第一个元素是调用模块和函数名
    # print("模块和函数名:%s" % module_func)
    # print("参数:%s" % params[1:])
    pos = module_func.find("::")
    module = module_func[:pos]  # 模块名
    func = module_func[pos + 2:]  # 函数名
    return module, func, params[1:]


class ProcessThread(threading.Thread):
    """
    preThread 处理线程
    """

    def __init__(self, client_socket):
        threading.Thread.__init__(self)

        # 客户socket
        self._socket = client_socket

    def run(self):

        start = datetime.datetime.now()
        start_clock = time.clock()

        # ---------------------------------------------------
        #    1.接收消息
        # ---------------------------------------------------

        try:
            self._socket.settimeout(TIMEOUT)  # 设置socket超时时间
            first_buf = self._socket.recv(16 * 1024)  # 接收第一个消息包(bytes)
            if len(first_buf) < REQUEST_MIN_LEN:  # 不够消息最小长度
                print("非法包,小于最小长度: %s" % first_buf)
                self._socket.close()
                return

            first_comma = index(first_buf, 0x2c)  # 查找第一个","分割符
            total_len = int(first_buf[0:first_comma])  # 消息包总长度
            print("消息长度:%d" % total_len)
            req_msg = first_buf[first_comma + 1:]
            while len(req_msg) < total_len:
                req_msg = req_msg + self._socket.recv(16 * 1024)

                # 调试
                # print ("请求包:%s" % req_msg)

        except Exception as e:
            print('接收消息异常', e)
            self._socket.close()
            return

        # ---------------------------------------------------
        #    2.调用模块、函数检查,预编译。
        # ---------------------------------------------------

        # 从消息包中解析出模块名、函数名、入参list
        module, func, params = parse_php_req(req_msg)

        if module not in pc_dict:  # 预编译字典中没有此编译模块
            # 检查模块、函数是否存在
            try:
                call_mod = __import__(module)  # 根据module名,反射出module
                pc_dict[module] = call_mod  # 预编译字典缓存此模块
            except Exception as e:
                print('模块不存在:%s' % module, e)
                self._socket.sendall(("F" + "module '%s' is not exist!" % module).encode(php_python.CHARSET))  # 异常
                self._socket.close()
                return
        else:
            call_mod = pc_dict[module]  # 从预编译字典中获得模块对象

        try:
            getattr(call_mod, func)
        except Exception as e:
            print('函数不存在:%s' % func, e)
            self._socket.sendall(("F" + "function '%s()' is not exist!" % func).encode(php_python.CHARSET))  # 异常
            self._socket.close()
            return

        # ---------------------------------------------------
        #    3.Python函数调用
        # ---------------------------------------------------

        try:
            params = ','.join([repr(x) for x in params])
            # print ("调用函数及参数:%s(%s)" % (module+'.'+func, params) )

            # 加载函数
            compile_str = "import %s\nret = %s(%s)" % (module, module + '.' + func, params)
            print("函数调用代码:%s" % compile_str)
            compile_func = compile(compile_str, "", "exec")

            if func not in global_env:
                global_env[func] = compile_func
            local_env = {}
            exec(compile_func, global_env, local_env)  # 函数调用
            # print (global_env)
            # print (local_env)
        except Exception as e:
            print('调用Python业务函数异常', e)
            err_type, err_msg, traceback = sys.exc_info()
            self._socket.sendall(("F%s" % err_msg).encode(php_python.CHARSET))  # 异常信息返回
            self._socket.close()
            return

        # ---------------------------------------------------
        #    4.结果返回给PHP
        # ---------------------------------------------------
        # retType = type(local_env['ret'])
        # print ("函数返回:%s" % retType)
        resp_str = json.dumps(local_env['ret'])  # 函数结果组装为PHP序列化字符串

        try:
            # 加上成功前缀'S'
            resp_str = "S" + resp_str
            # 调试
            # print ("返回包:%s" % resp_str)
            self._socket.sendall(resp_str.encode(php_python.CHARSET))
        except Exception as e:
            print('发送消息异常', e)
            err_type, err_msg, traceback = sys.exc_info()
            self._socket.sendall(("F%s" % err_msg).encode(php_python.CHARSET))  # 异常信息返回
        finally:
            self._socket.close()

            end = datetime.datetime.now()
            end_clock = time.clock()

            start_str = start.strftime('%H:%M:%S')
            end_str = end.strftime('%H:%M:%S')
            print("开始时间:%s" % start_str)
            print("结束时间:%s" % end_str)
            print("读取时间 %d 秒" % (end.timestamp() - start.timestamp()))
            print("CPU时间 %d" % (end_clock - start_clock))
            return