python TCP套接字服务器v1.1-新增服务端命令功能及修改bug(socket+PyQt5)

TCP聊天服务器套接字v1.1

所有版本记录:
v1.0 : TCP聊天服务器套接字|PyQt5+socket(TCP端口映射+端口放行)+logging+Thread(含日志,html)+anaconda打包32位exe(3.4万字)|python高阶

| 1. 服务器代码改进 / bug改进

(1).发送函数改为@function

class Server():
	...
    def send(self, sock, user, mes):
        self.QUIT(user, lambda: sock.sendall(mes.encode(self.encode)))()
    def send(self, sock, user, mes):
        @self.QUIT(user)
        def func():
            sock.sendall(mes.encode(self.encode))
        return func()

(2).异常运行函数改为三叠函数


    def QUIT(self, user, command):
        sock = list(self.connect.keys())[list(self.connect.values()).index(user)]
        def logs(*args, **kargs):
            try:
                command(*args, **kargs)
            except:
                self.errs.append(sock)
        return logs
    def QUIT(self, user):
        sock = list(self.connect.keys())[list(self.connect.values()).index(user)]
        def prop(command, *args, **kwargs):
            def logs(*args, **kwargs):
                try:
                    command(*args, **kwargs)
                    return True
                except:
                    logging.exception(str())
                    if self.errduring is False:
                        self.errs.append((sock,user)) #在遍历时列表增加 -> 触发RuntimeError
                    return False
            return logs
        return prop

(3).服务端在下线时列表在遍历时 增加下线的服务端 -> 触发RuntimeError

bug改进方法:
增加errduring; inc参数


    def ServerMessage(self, mes):
        for sock, user in self.connect.items():
            if not sock in self.errs:
                self.send(sock, user, mes)
    def UserMessage(self, address, _user, mes):
        if not mes:
            return
        mes = mes.decode(encoding="utf8")
        for sock, user in self.connect.items():
            if not sock in self.errs:
                send_message = Server.user_message % ("brown" if _user == user else "red",
                                                      _user,
                                                      address,
                                                      "(我自己)" if _user == user else "",
                                                      mes)
                self.send(sock, user, send_message)
        logger.info(f"{
     address}[{
     _user}] : {
     mes}")
        self.error_handle()
    def error_handle(self):
        for sock in self.errs:
            sock.close()
            logger.exception(msg = str())
            Q = Server.quit_message % user
            logger.info(Q)
            self.connect.pop(sock)
            self.ServerMessage(Q)
    def ServerMessage(self, mes, inc=True):
        self.errduring = True
        for sock, user in self.connect.items():
            if not sock in self.errs:
                self.send(sock, user, mes)
        if inc:
            self.error_handle()
        self.errduring = False
        
    def UserMessage(self, address, _user, mes,inc=True):
        if not mes:
            return
        self.errduring = True
        for sock, user in self.connect.items():
            if not sock in self.errs:
                send_message = Server.user_message % ("brown" if _user == user else "red",
                                                      _user,
                                                      address,
                                                      "(我自己)" if _user == user else "",
                                                      mes)
                self.send(sock, user, send_message)
        logger.info(f"{
     address}[{
     _user}] : {
     mes}")
        if inc:
            self.error_handle()
        self.errduring = False
        
    def error_handle(self):
        for _, user in self.errs: #使用变量_ : 为了防止触发KeyError: <socket.socket [closed] fd=-1, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0>
            if user in list(self.connect.values()):
                sock = list(self.connect.keys())[list(self.connect.values()).index(user)]
                logger.exception(msg = str())
                Q = Server.quit_message % (user, self._str_sockets())
                logger.info(Q)
                self.connect.pop(sock) 
                self.ServerMessage(Q, False) #防止多次调用error_handle函数
                sock.close()

(4)获取真正本机的ip地址

如果直接用socket.gethostbyname(socket.gethostname())获取地址,很有可能是错误的(Vmware虚拟机的地址127.0.0.1等)

搜索后我得到了下面这段精巧的代码:

...
def get_host_ip() -> str:
    """get current IP address"""
    try:
        s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        s.connect(('8.8.8.8', 80))
        ip = s.getsockname()[0]
    finally:
        s.close()
    return ip

通过UDP尝试连接8.8.8.8:80,不管是否连接成功,获得的本机IP一定是正确的。在Ubuntu(kivydev)和Windows上都可用,还省去了判断操作系统的大段代码.

那么代码可以改为:

server = Server(socket.gethostname(),429)
server = Server(get_host_ip(),429)

| 2.新增命令功能 (在输入框添加"/")

class Command_Handler(object):
    def __init__(self, bind=None):
        """Bind Server class"""
        self.bind = bind
    def _function(self, _list, client):
        
        data = {
   "/info" : {
   "-v": self.get_version(),
                           "-id" : self.get_id(client),
                           "-i" : self.info(),
                           "-h" : self.help()},
                }
        _dict = data
        for n in range(len(_list)):
            if type(_dict) == dict:
                _dict = _dict.get(_list[n],  self.unknown(" ".join(_list)))
            else:
                break
        if  type(_dict) == dict:
             _dict = "Error:\n<font color='blue'>This command must take more arguments. Such as %s.</font>" % list(_dict.keys()) 
        return _dict
    @staticmethod
    def help():
        return """/info [-v] [-id] [-i]
-v : get version of program.
-id : get your id.
-i : get information.
-h : help.
For example, <font color=red>/info -id</font>"""
    @staticmethod
    def get_version():
        return "version : " + str(__version__)
    def get_id(self, client):
        return "Your id is {}.".format(id(client))
    
    def info(self):
        return f"Socket Server[version {
     self.get_version()}] By zmh."
    def unknown(self,s):
        return """Error:
No command named "%s". Please search [/info -h] to help.
%s""" % (s, self.help()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值