ggntalk 2021-07-23

ggntalk 2021-07-23 应用版

# -*- encoding: utf-8 -*-

"""
    ggntalk (曾经) 是 ggn_2015 闲的无聊开发的 python3 下的通讯工具
    后来 ggn_2015 删去了大部分功能,剩下一个很智障的的基于 socket 的通讯库
    import ggntalk 后,在命令行中输入 ggntalk.help() 显示帮助信息
    力争打造简洁易懂的中文 __doc__ 文档
"""

# 一些约定
# 1. 所有函数名都用小写字母,单词之间用下划线连接
# 2. 定义指令函数时,一定要设置对应的 HELPLIST 和 FUNCLIST
# 3. 定义函数时,一定要定义函数的 __doc__

import socket  # 套接字通信
import _thread # 多线程
import time    # 计时函数
import traceback # 错误信息反馈
import json    # 打开 json 文件


AUTHOR  = "GGN_2015"
VERSION = "2021-07-23" # 版本号用日期表示


NAMELIST = [] # 指令名序列
FUNCLIST = {} # 函数映射: 函数名 -> 函数对象 的映射


def add_instruction(ins_name, ins_object): # 添加一个指令
    """
        指令名: add_instruction
        原型: add_instruction(ins_name, ins_object, ins_message)
        功能: 在帮助列表中注册一个命令
    """
    FUNCLIST[ins_name] = ins_object
    NAMELIST.append(ins_name)
    NAMELIST.sort() # 每次插入后暴力排序

add_instruction("add_instruction", add_instruction)


def help(ins_name = ""): # 输出帮助文档
    """
        指令名: help
        原型: help(ins_name = "")
        功能: ins_name = "" 时输出指令列表,否则输出某个指令对应的 __doc__ 信息。
    """
    if ins_name == "": # 无参数的情况
        print("ggntalk VERSION = %s, AUTHOR = %s, 所有命令如下:" % (VERSION, AUTHOR))
        if len(NAMELIST) == 0:
            print("    <Empty>") # 指令列表为空
        else:
            for x in NAMELIST: # 输出指令序列
                print("    " + x)
        print("") # 输出空行
    else:
        if FUNCLIST.get(ins_name) != None: # 指令存在
            print(FUNCLIST[ins_name].__doc__) # 输出对应的文档
        else:
            print("help: 未找到对应的指令")

add_instruction("help", help) # 添加 help 函数


def client_send(server_ip, server_port, message, receive_len = 1048576):
    """
        指令名: client_send
        原型: client_send(server_ip, server_port, message, receive_len = 1048576)
        功能: 客户端向服务器发送消息并接收服务器返回的信息
        要求: server_port 必须是一个 0 ~ 65535 之间的整数, receive_len 的单位是字节
        注: 默认采用 UTF-8 方式对发送的信息进行编码
    """
    client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    try:
        client_socket.connect((server_ip, server_port))
        client_socket.send(message.encode("utf-8"))
        re_message = client_socket.recv(receive_len) # 接收来自服务器的回复信息
        client_socket.close()
        return re_message.decode("utf-8") # 返回值是来自服务器的回复信息
    except:
        client_socket.close()
        return traceback.format_exc() 

add_instruction("client_send", client_send) # 添加 client_send 函数


def start_new_thread(func_object, argu_list = ()): # 其实就是在原基础上套了个壳
    """
        指令名: start_new_thread
        原型: start_new_thread(func_object, argu_list = ())
        功能: 启动一个新的线程以执行某个函数
    """
    _thread.start_new_thread(func_object, argu_list)

add_instruction("start_new_thread", start_new_thread) # 这个方法是启动服务器的方法


def feedback(message, connection_socket, addr, func_object): # 给客户端提供反馈信息
    """
        函数名: feedback
        函数原型: feedback(message, connecttion_socket, addr, func_object)
        功能:用于将信息反馈给客户端,建议采用多线程的方式调用
    """
    re_message = func_object(message, addr) # 计算返回值
    connection_socket.send(re_message.encode("utf-8")) # 将计算结果编码并传回
    connection_socket.close() # 结束 socket 连接

add_instruction("feedback", feedback)


def run_server(server_object): # 启动服务器
    """
        指令名: run_server
        原型: run_server(server_object)
        功能: 启动一个初始化后的服务器
        注: server_object 是一个已经准备就绪的 server_object 对象
    """
    while server_object.running: # 如果服务器仍在进行
        print("服务器正在监听中 ip = %s port = %s ..." % (server_object.server_ip, server_object.server_port))
        try:
            connection_socket, addr = server_object.accept()
        except Exception as ex: # 这句话是 python3 写法
            print("    服务器 " + str(ex)) # 输出异常信息
        else:
            print("    得到来自 " + str(addr) + " 的数据信息")
            message = connection_socket.recv(server_object.receive_len).decode("utf-8") # 得到客户端反馈的消息
            _thread.start_new_thread(feedback, (message, connection_socket, addr, server_object.func_object)) # 多线程的服务器反馈机制
    print("服务器运行结束 ip = %s port = %s ..." % (server_object.server_ip, server_object.server_port))

class server_object(object):
    """
        类型名: server_object
        功能: 该类型用来描述一个服务器的运行过程
        成员列表: 
            func_object     负责根据客户需求计算反馈信息,需要接收
            receive_len     服务器接收单条消息的最大字节数,默认 1048576 Byte
            running         = True 表示正在运行(默认), = False 表示服务器停止
            server_ip       服务器的广域网/局域网 ip 地址
            server_port     服务器的运行端口,类型为整数
            server_socket   服务端对象
    """
    def __init__(self, server_ip, server_port, func_object, receive_len = 1048576):
        """
            函数名: server_object.__init__
            函数原型: __init__(self, func_object)
            要求: func_object 是一个函数,接收一个字符串参数和 一个 addr 参数,返回一个字符串参数
        """
        self.func_object = func_object
        self.server_ip = server_ip
        self.server_port = server_port
        self.running = True # 默认状态是运行状态
        self.receive_len = receive_len

        self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 服务端对象
        self.server_socket.bind ((server_ip, server_port))
        self.server_socket.listen(128) # 最大监听数
        self.server_socket.settimeout(10) # 设置超时时限 10 s

    def start(self): # 一个服务器只能启动一次,并且启动一个进程
        start_new_thread(run_server, (self, ))

    def restart(self): # 先停止运行, 再根据新的服务器设定, 重新启动服务器
        print("    正在重启服务器 ...")
        self.stop()
        print("    耐心等待 12 秒后服务器重启 ...")
        time.sleep(12) # 需要等待上一个服务器彻底结束才能开始新的服务器
        self.running = True
        self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 服务端对象
        self.server_socket.bind ((self.server_ip, self.server_port))
        self.server_socket.listen(128) # 最大监听数
        self.server_socket.settimeout(10) # 设置超时时限 10 s
        self.start()


    def accept(self): # 等待接收信息
        return self.server_socket.accept()

    def stop(self): # 命令服务器停止执行
        print("    正在停止服务器 ...")
        self.running = False
        
add_instruction("server_object", server_object)


def test_server_function(message, addr):
    """
        函数名: test_server_function
        函数原型: test_server_function(message, addr)
        功能: 为了测试服务器而设计的轻量级服务函数,功能为对 message 执行 eval 后以字符串返回
    """
    try:
        return str(eval(message)) # 在本地得出计算结果后返回
    except:
        return traceback.format_exc() # 出错返回错误信息

add_instruction("test_server_function", test_server_function)


def run_server_by_config(server_object, config_filename = "config.json"):
    """
        指令名: run_server_by_config
        原型: run_server_by_config(server_object, config_filename = "config.json")
        功能: 根据 config.json 中的数据决定服务器是否运行,以及运行的端口号
        运行方式: 不建立新的线程
    """
    server_object.start() # 启动服务器
    while True:
        try:
            with open(config_filename) as f:
                config = json.load(f)
        except Exception as ex:
            print(traceback.format_exc()) # 执行到这里应该是因为 config 文件没有找到
            server_object.stop()
            return False # 服务器启动失败
        else:
            # 找到了 config 文件,如果 config 中内容与当前服务器不同,重启服务器
            changed = False # 用来记录设置是否发生了改变
            if config.get("server_ip") != None and server_object.server_ip != config["server_ip"]: # 服务器 ip 设置改变
                changed = True
                print("    服务器求改运行的 ip 为: " + config["server_ip"])
                server_object.server_ip = config["server_ip"]
            if config.get("server_port") != None and server_object.server_port != config["server_port"]: # 服务器端口设置改变
                changed = True
                print("    服务器修改运行的端口为: " +str(config["server_port"])) # 端口号必须为整数
                server_object.server_port = config["server_port"]
            if config.get("running") != None and not config["running"]: # 让服务器立即停止
                server_object.stop()
                print("    根据 config.json 中的信号, 服务器停止运行")
                return True # 服务器运行结束
            if changed: # 如果服务器设置发生了改变
                server_object.restart() # 重启服务器
            time.sleep(5) # 每 5 秒钟检查一次设置

add_instruction("run_server_by_config", run_server_by_config)


def stop_server_by_config(config_filename = "config.json"): # 利用文件耦合关闭服务器
    """
        函数名: stop_server_by_config
        函数原型: stop_server_by_config(config_filename = "config.json")
        功能: 利用文件耦合关闭服务器
    """
    try:
        with open(config_filename) as f:
            config = json.load(f)
    except Exception as e:
        print(traceback.format_exc()) # 输出出错信息
    else:
        config["running"] = False # 先设置 config 中的 running 为 false
        with open(config_filename, "w") as f:
            json.dump(config, f, indent=4)
        print("正在利用 config 文件停止服务器,请等待十四秒 ...")
        time.sleep(14)
        config["running"] = True # 等待服务器结束后,再重新将服务器的 running 设为 true
        with open(config_filename, "w") as f:
            json.dump(config, f, indent=4)
        print("    设置完成")

add_instruction("stop_server_by_config", stop_server_by_config)


if __name__ == "__main__": # 用于对程序进行调试
    print("ggntalk 加载成功, VERSION = %s, AUTHOR = %s" % (VERSION, AUTHOR)) # 加载成功
    server = server_object("127.0.0.1", 12345, test_server_function)
    run_server_by_config(server) # 根据 config.json 中的数据启动服务器

ggntalk 2021-07-23 BETA 测试版

# -*- encoding: utf-8 -*-

"""
    ggntalk (曾经) 是 ggn_2015 闲的无聊开发的 python3 下的通讯工具
    后来 ggn_2015 删去了大部分功能,剩下一个很智障的的基于 socket 的通讯库
    import ggntalk 后,在命令行中输入 ggntalk.help() 显示帮助信息
    力争打造简洁易懂的中文 __doc__ 文档
"""

# 一些约定
# 1. 所有函数名都用小写字母,单词之间用下划线连接
# 2. 定义指令函数时,一定要设置对应的 HELPLIST 和 FUNCLIST
# 3. 定义函数时,一定要定义函数的 __doc__

import socket  # 套接字通信
import _thread # 多线程
import time    # 计时函数
import traceback # 错误信息反馈
import json    # 打开 json 文件


AUTHOR  = "GGN_2015"
VERSION = "2021-07-23 BETA" # 版本号用日期表示


NAMELIST = [] # 指令名序列
FUNCLIST = {} # 函数映射: 函数名 -> 函数对象 的映射


def add_instruction(ins_name, ins_object): # 添加一个指令
    """
        指令名: add_instruction
        原型: add_instruction(ins_name, ins_object, ins_message)
        功能: 在帮助列表中注册一个命令
    """
    FUNCLIST[ins_name] = ins_object
    NAMELIST.append(ins_name)
    NAMELIST.sort() # 每次插入后暴力排序

add_instruction("add_instruction", add_instruction)


def help(ins_name = ""): # 输出帮助文档
    """
        指令名: help
        原型: help(ins_name = "")
        功能: ins_name = "" 时输出指令列表,否则输出某个指令对应的 __doc__ 信息。
    """
    if ins_name == "": # 无参数的情况
        print("ggntalk VERSION = %s, AUTHOR = %s, 所有命令如下:" % (VERSION, AUTHOR))
        if len(NAMELIST) == 0:
            print("    <Empty>") # 指令列表为空
        else:
            for x in NAMELIST: # 输出指令序列
                print("    " + x)
        print("") # 输出空行
    else:
        if FUNCLIST.get(ins_name) != None: # 指令存在
            print(FUNCLIST[ins_name].__doc__) # 输出对应的文档
        else:
            print("help: 未找到对应的指令")

add_instruction("help", help) # 添加 help 函数


def client_send(server_ip, server_port, message, receive_len = 1048576):
    """
        指令名: client_send
        原型: client_send(server_ip, server_port, message, receive_len = 1048576)
        功能: 客户端向服务器发送消息并接收服务器返回的信息
        要求: server_port 必须是一个 0 ~ 65535 之间的整数, receive_len 的单位是字节
        注: 默认采用 UTF-8 方式对发送的信息进行编码
    """
    client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    try:
        client_socket.connect((server_ip, server_port))
        client_socket.send(message.encode("utf-8"))
        re_message = client_socket.recv(receive_len) # 接收来自服务器的回复信息
        client_socket.close()
        return re_message.decode("utf-8") # 返回值是来自服务器的回复信息
    except:
        client_socket.close()
        return traceback.format_exc() 

add_instruction("client_send", client_send) # 添加 client_send 函数


def start_new_thread(func_object, argu_list = ()): # 其实就是在原基础上套了个壳
    """
        指令名: start_new_thread
        原型: start_new_thread(func_object, argu_list = ())
        功能: 启动一个新的线程以执行某个函数
    """
    _thread.start_new_thread(func_object, argu_list)

add_instruction("start_new_thread", start_new_thread)


def run_server(server_object): # 启动服务器
    """
        指令名: run_server
        原型: run_server(server_object)
        功能: 启动一个初始化后的服务器
        注: server_object 是一个已经准备就绪的 server_object 对象
    """
    while server_object.running: # 如果服务器仍在进行
        print("服务器正在监听中 ip = %s port = %s ..." % (server_object.server_ip, server_object.server_port))
        try:
            connection_socket, addr = server_object.accept()
        except Exception as ex: # 这句话是 python3 写法
            print("    服务器 " + str(ex)) # 输出异常信息
        else:
            print("    得到来自 " + str(addr) + " 的数据信息")
            message = connection_socket.recv(server_object.receive_len)
            connection_socket.send(server_object.func_object(message, addr).encode("utf-8")) # 利用 func_object 计算反馈信息
            connection_socket.close()
    print("服务器运行结束 ip = %s port = %s ..." % (server_object.server_ip, server_object.server_port))

class server_object(object):
    """
        类型名: server_object
        功能: 该类型用来描述一个服务器的运行过程
        成员列表: 
            func_object     负责根据客户需求计算反馈信息,需要接收
            receive_len     服务器接收单条消息的最大字节数,默认 1048576 Byte
            running         = True 表示正在运行(默认), = False 表示服务器停止
            server_ip       服务器的广域网/局域网 ip 地址
            server_port     服务器的运行端口,类型为整数
            server_socket   服务端对象
    """
    def __init__(self, server_ip, server_port, func_object, receive_len = 1048576):
        """
            函数名: server_object.__init__
            函数原型: __init__(self, func_object)
            要求: func_object 是一个函数,接收一个字符串参数和 一个 addr 参数,返回一个字符串参数
        """
        self.func_object = func_object
        self.server_ip = server_ip
        self.server_port = server_port
        self.running = True # 默认状态是运行状态
        self.receive_len = receive_len

        self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 服务端对象
        self.server_socket.bind ((server_ip, server_port))
        self.server_socket.listen(128) # 最大监听数
        self.server_socket.settimeout(10) # 设置超时时限 10 s

    def start(self): # 一个服务器只能启动一次,并且启动一个进程
        start_new_thread(run_server, (self, ))

    def restart(self): # 先停止运行, 再根据新的服务器设定, 重新启动服务器
        print("    正在重启服务器 ...")
        self.stop()
        print("    耐心等待 12 秒后服务器重启 ...")
        time.sleep(12) # 需要等待上一个服务器彻底结束才能开始新的服务器
        self.running = True
        self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 服务端对象
        self.server_socket.bind ((self.server_ip, self.server_port))
        self.server_socket.listen(128) # 最大监听数
        self.server_socket.settimeout(10) # 设置超时时限 10 s
        self.start()


    def accept(self): # 等待接收信息
        return self.server_socket.accept()

    def stop(self): # 命令服务器停止执行
        print("    正在停止服务器 ...")
        self.running = False
        
add_instruction("server_object", server_object)


def test_server_function(message, addr):
    """
        函数名: test_server_function
        函数原型: test_server_function(message, addr)
        功能: 为了测试服务器而设计的轻量级服务函数,功能为对 message 执行 eval 后以字符串返回
    """
    try:
        return str(eval(message)) # 在本地得出计算结果后返回
    except:
        return traceback.format_exc() # 出错返回错误信息

add_instruction("test_server_function", test_server_function)


def run_server_by_config(server_object, config_filename = "config.json"):
    """
        指令名: run_server_by_config
        原型: run_server_by_config(server_object, config_filename = "config.json")
        功能: 根据 config.json 中的数据决定服务器是否运行,以及运行的端口号
        运行方式: 不建立新的线程
    """
    server_object.start() # 启动服务器
    while True:
        try:
            with open(config_filename) as f:
                config = json.load(f)
        except Exception as ex:
            print(traceback.format_exc()) # 执行到这里应该是因为 config 文件没有找到
            server_object.stop()
            return False # 服务器启动失败
        else:
            # 找到了 config 文件,如果 config 中内容与当前服务器不同,重启服务器
            changed = False # 用来记录设置是否发生了改变
            if config.get("server_ip") != None and server_object.server_ip != config["server_ip"]: # 服务器 ip 设置改变
                changed = True
                print("    服务器求改运行的 ip 为: " + config["server_ip"])
                server_object.server_ip = config["server_ip"]
            if config.get("server_port") != None and server_object.server_port != config["server_port"]: # 服务器端口设置改变
                changed = True
                print("    服务器修改运行的端口为: " +str(config["server_port"])) # 端口号必须为整数
                server_object.server_port = config["server_port"]
            if config.get("running") != None and not config["running"]: # 让服务器立即停止
                server_object.stop()
                print("    根据 config.json 中的信号, 服务器停止运行")
                return True # 服务器运行结束
            if changed: # 如果服务器设置发生了改变
                server_object.restart() # 重启服务器
            time.sleep(5) # 每 5 秒钟检查一次设置

add_instruction("run_server_by_config", run_server_by_config)


def stop_server_by_config(config_filename = "config.json"): # 利用文件耦合关闭服务器
    """
        函数名: stop_server_by_config
        函数原型: stop_server_by_config(config_filename = "config.json")
        功能: 利用文件耦合关闭服务器
    """
    try:
        with open(config_filename) as f:
            config = json.load(f)
    except Exception as e:
        print(traceback.format_exc()) # 输出出错信息
    else:
        config["running"] = False # 先设置 config 中的 running 为 false
        with open(config_filename, "w") as f:
            json.dump(config, f, indent=4)
        print("正在利用 config 文件停止服务器,请等待十四秒 ...")
        time.sleep(14)
        config["running"] = True # 等待服务器结束后,再重新将服务器的 running 设为 true
        with open(config_filename, "w") as f:
            json.dump(config, f, indent=4)
        print("    设置完成")

add_instruction("stop_server_by_config", stop_server_by_config)


if __name__ == "__main__": # 用于对程序进行调试
    print("ggntalk 加载成功, VERSION = %s, AUTHOR = %s" % (VERSION, AUTHOR)) # 加载成功
    server = server_object("127.0.0.1", 12345, test_server_function)
    run_server_by_config(server) # 根据 config.json 中的数据启动服务器

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值