From 20331bf2e451e0712b440bd9aecbf45cf1c5b4fa Mon Sep 17 00:00:00 2001 From: Fengyi Chen Date: Thu, 25 Jul 2024 21:45:21 +0800 Subject: [PATCH 1/6] Create .DS_Store --- .DS_Store | Bin 0 -> 6148 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 .DS_Store diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..e507b0eb9bfa4aed140eb881470964b869a03e13 GIT binary patch literal 6148 zcmeHK%}T>S5dO9Xtf<(d$AAYfD)#0{Vu^P_JS+X77F$!adJaB zW_M|`jV(Qi$PCPWo7tJ&$(NAH05FZab{(hzs8R(hD;$0hSr;uy#aq^hM)v4;>!+=3 zFf4hh;jc0v&o06qy69mPKEJ2;;@Tif(`G+w(pG(Y{n+{3emM%)+jG~4mxXtuB3ok_ zZFF#pD~ym~7@ofIT=ppD@OTiNpST>R_8DZ8OlErp`Pla#>&&Ht8{FG*7cKP3N(a}| z%xv|T+Z^v=o)3p#XFkul5tE!3iwN`I7d};#0cAiLSd;c&Dx=`a=4CBISkG)^wF?Z;~VSMvp z{K>|5D8`=7{bTD6lQ`5-8Bhj72A14qP3r&g?EXIt(ko>^8TeNWm?%9>8@wf7TT3@5 uwKk?+P({QqcQ_8=#Fk?EN-5r?TA@9b2{G}QJEVo8KLVBp9h8AzW#AiA*K?@= literal 0 HcmV?d00001 From c7ba0b25358c92391d3ced3be9da45911d3e59c0 Mon Sep 17 00:00:00 2001 From: Fengyi Chen Date: Thu, 25 Jul 2024 21:46:49 +0800 Subject: [PATCH 2/6] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E4=BA=86=E6=9C=8D?= =?UTF-8?q?=E5=8A=A1=E7=AB=AF=EF=BC=8C=E6=96=B0=E5=A2=9E=E5=B0=81=E7=A6=81?= =?UTF-8?q?=E7=B3=BB=E7=BB=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server-client/main.py | 133 ++++++++++++++++++++++++++++++------------ 1 file changed, 97 insertions(+), 36 deletions(-) diff --git a/server-client/main.py b/server-client/main.py index dad909c..b3e8e44 100755 --- a/server-client/main.py +++ b/server-client/main.py @@ -1,7 +1,7 @@ import json import threading from socket import * -from time import ctime +from time import ctime, time class PyChattingServer: __socket = socket(AF_INET, SOCK_STREAM, 0) @@ -14,7 +14,10 @@ class PyChattingServer: self.__msg_handler = ChattingHandler() def start_session(self): - print('即时聊天系统部署完成,用户可通过客户端并输入本机IP访问!\r\n') + print('已经上线,用户可通过IP进入\r\n') + input_thread_handler = threading.Thread(target=self.input_thread) + input_thread_handler.daemon = True + input_thread_handler.start() try: while True: cs, caddr = self.__socket.accept() @@ -23,37 +26,70 @@ class PyChattingServer: except socket.error: pass + def input_thread(self): + while True: + command = input("") + self.__msg_handler.add_to_blacklist_manual(command.strip()) + class ChattingThread(threading.Thread): - __buf = 1024 + __buf = 32767 def __init__(self, cs, caddr, msg_handler): super(ChattingThread, self).__init__() self.__cs = cs self.__caddr = caddr self.__msg_handler = msg_handler + self.__last_msg_time = time() + self.__msg_count = 0 def run(self): try: - print('> 连接来自于:', self.__caddr) - data = "欢迎你到来由Pixel Chat驱动的聊天室,开始聊天前请你阅读以下须知\r\n"\ - "1. 请勿发表辱骂他人的言论\r\n"\ - "2. 请勿发表违反国家法律的言论\r\n"\ - "3. 请勿刷屏\r\n"\ - "4. 本聊天工具没有换行,一行写完回车即发送\r\n"\ - "如果您同意以上协议,请输入你的的昵称(不能带空格)并开始聊天:" + print('-> 连接来自于:', self.__caddr) + if self.__msg_handler.is_blacklisted(self.__caddr[0]): + self.__handle_blacklisted() + return + data = "欢迎你到来暑期聊天室!请遵守以下规则:\r\n"\ + "1. 不要刷屏,否则将会被踢出\r\n"\ + "2. 不要骂人,可以吐槽,但要适度\r\n"\ + "3. 如有问题请联系服务器管理员\r\n"\ + "4. 不要发布违反国家法律的信息\r\n"\ + "如果你同意以上内容,请输入昵称加入服务器~" self.__cs.sendall(bytes(data, 'utf-8')) while True: + if self.__msg_handler.is_blacklisted(self.__caddr[0]): + self.__handle_blacklisted() + return data = self.__cs.recv(self.__buf).decode('utf-8') if not data: break + if len(data) > 15000: + self.__msg_handler.add_to_blacklist(self.__caddr[0]) + self.__handle_blacklisted() + return + current_time = time() + if current_time - self.__last_msg_time < 12: # 12秒内发送多条消息 + self.__msg_count += 1 + if self.__msg_count > 12: + self.__msg_handler.add_to_blacklist(self.__caddr[0]) + self.__handle_blacklisted() + return + else: + self.__msg_count = 0 + self.__last_msg_time = current_time self.__msg_handler.handle_msg(data, self.__cs) print(data) - except: - pass + except Exception as e: + print(f"Error in thread: {e}") finally: self.__msg_handler.close_conn(self.__cs) self.__cs.close() + def __handle_blacklisted(self): + print('...黑塔安全拦截的用户:', self.__caddr) + data = '拒绝访问!请联系seventeen@ohdragonboi.cn' + self.__cs.sendall(bytes(data, 'utf-8')) + self.__cs.close() + class ChattingHandler: __help_str = "[ 系统消息 ]\r\n" \ "输入/checkol,即可获得所有登陆用户信息\r\n" \ @@ -64,11 +100,12 @@ class ChattingHandler: "再次输入/i,即可取消屏蔽\r\n" \ "所有首字符为/的信息都不会发送出去" - __buf = 1024 + __buf = 32767 __socket_list = [] __user_name_to_socket = {} __socket_to_user_name = {} __user_name_to_broadcast_state = {} + __blacklist = set() def start_thread(self, cs, caddr): self.__socket_list.append(cs) @@ -87,7 +124,7 @@ class ChattingHandler: self.__socket_to_user_name.pop(cs) self.__user_name_to_broadcast_state.pop(nickname) nickname += " " - self.broadcast_system_msg(nickname + "离开了本聊天室,他的用户名 " + nickname + "现在开放注册") + self.broadcast_系统消息_msg(nickname + "离开了本聊天室") def handle_msg(self, msg, cs): js = json.loads(msg) @@ -97,7 +134,7 @@ class ChattingHandler: self.send_to(json.dumps({ 'type': 'login', 'success': False, - 'msg': '账号禁止包含空格!' + 'msg': '账号不能够带有空格' }), cs) else: self.__user_name_to_socket[js['msg']] = cs @@ -108,12 +145,12 @@ class ChattingHandler: 'success': True, 'msg': '昵称建立成功,输入/checkol可查看所有在线的人,输入/help可以查看帮助(所有首字符为/的消息都不会发送)' }), cs) - self.broadcast_system_msg(js['msg'] + "加入了聊天") + self.broadcast_系统消息_msg(js['msg'] + "加入了聊天") else: self.send_to(json.dumps({ 'type': 'login', 'success': False, - 'msg': '账号已存在,请换一个重试' + 'msg': '账号已存在' }), cs) elif js['type'] == "broadcast": if self.__user_name_to_broadcast_state[self.__socket_to_user_name[cs]]: @@ -121,7 +158,7 @@ class ChattingHandler: else: self.send_to(json.dumps({ 'type': 'broadcast', - 'msg': '屏蔽模式下无法发送群聊信息,输入/i可取消屏蔽' + 'msg': '屏蔽模式下无法发送群聊信息,输入/i解除屏蔽' }), cs) elif js['type'] == "ls": self.send_to(json.dumps({ @@ -143,20 +180,13 @@ class ChattingHandler: def exchange_ignore_state(self, cs): if cs in self.__socket_to_user_name: state = self.__user_name_to_broadcast_state[self.__socket_to_user_name[cs]] - if state: - state = False - else: - state = True - self.__user_name_to_broadcast_state.pop(self.__socket_to_user_name[cs]) + state = not state self.__user_name_to_broadcast_state[self.__socket_to_user_name[cs]] = state - if self.__user_name_to_broadcast_state[self.__socket_to_user_name[cs]]: - msg = "通常模式" - else: - msg = "屏蔽模式" + msg = "通常模式" if state else "屏蔽模式" self.send_to(json.dumps({ 'type': 'ignore', 'success': True, - 'msg': '[%s]\r\n[ 系统消息 ] : %s\r\n' % (ctime(), "模式切换成功,现在是" + msg) + 'msg': '[ %s ]\r\n[ 系统消息 ] : %s\r\n' % (ctime(), "模式切换成功,现在是" + msg) }), cs) else: self.send_to({ @@ -167,7 +197,7 @@ class ChattingHandler: def single_chatting(self, cs, nickname, msg): if nickname in self.__user_name_to_socket: - msg = '[%s]\r\n[ %s 发送给 %s ] : %s\r\n' % ( + msg = '[ %s ]\r\n[ %s 发送给 %s ] : %s\r\n' % ( ctime(), self.__socket_to_user_name[cs], nickname, msg) self.send_to_list(json.dumps({ 'type': 'single', @@ -185,9 +215,9 @@ class ChattingHandler: self.send_to(msg, cs[i]) def get_all_login_user_info(self): - login_list = "[ 系统消息 ] 当前在线 : " + login_list = "[ 系统消息 ] 在线用户 : " for key in self.__socket_to_user_name: - login_list += self.__socket_to_user_name[key] + "," + login_list += self.__socket_to_user_name[key] + " | " return login_list def send_to(self, msg, cs): @@ -195,10 +225,10 @@ class ChattingHandler: self.__socket_list.append(cs) cs.sendall(bytes(msg, 'utf-8')) - def broadcast_system_msg(self, msg): - data = '[%s]\r\n[ 系统消息 ] : %s' % (ctime(), msg) + def broadcast_系统消息_msg(self, msg): + data = '[ %s ]\r\n[ 系统消息 ] : %s' % (ctime(), msg) js = json.dumps({ - 'type': 'system_msg', + 'type': '系统消息_msg', 'msg': data }) for i in range(len(self.__socket_list)): @@ -206,7 +236,7 @@ class ChattingHandler: self.__socket_list[i].sendall(bytes(js, 'utf-8')) def broadcast(self, msg, cs): - data = '[%s]\r\n[%s] : %s\r\n' % (ctime(), self.__socket_to_user_name[cs], msg) + data = '[ %s ]\r\n[%s] : %s\r\n' % (ctime(), self.__socket_to_user_name[cs], msg) js = json.dumps({ 'type': 'broadcast', 'msg': data @@ -216,10 +246,41 @@ class ChattingHandler: and self.__user_name_to_broadcast_state[self.__socket_to_user_name[self.__socket_list[i]]]: self.__socket_list[i].sendall(bytes(js, 'utf-8')) + def is_blacklisted(self, ip): + return ip in self.__blacklist + + def add_to_blacklist(self, ip): + self.__blacklist.add(ip) + + def add_to_blacklist_manual(self, ip): + if ip == '.ban': + ip = input("请输入需要封禁的ip地址:") + if not self.is_blacklisted(ip): + self.__blacklist.add(ip) + print(f"IP {ip} 已被手动加入黑名单") + else: + print(f"IP {ip} 已经在黑名单中") + elif ip == '.unban': + ip = input("请输入需要解除封禁的ip地址:") + if not self.is_blacklisted(ip): + print(f"IP {ip} 未在黑名单中") + else: + self.__blacklist.remove(ip) + print(f"IP {ip} 已经被手动移除") + elif ip == '.banlist': + print(self.__blacklist) + elif ip == '.help': + print("BAN: 封禁某个IP\r\n"\ + "UNBAN: 解除封禁某个IP\r\n"\ + "BANLIST: 查看封禁IP列表\r\n"\ + "HELP: 查看操作帮助") + else: + print("不存在的命令!") + def main(): server = PyChattingServer() server.start_session() -if __name__ == "__main__" : +if __name__ == "__main__": main() From bcd3df86803c155d0ca78a19b6d1a44d79222a55 Mon Sep 17 00:00:00 2001 From: Fengyi Chen Date: Sat, 27 Jul 2024 14:19:42 +0800 Subject: [PATCH 3/6] Update .DS_Store --- .DS_Store | Bin 6148 -> 6148 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/.DS_Store b/.DS_Store index e507b0eb9bfa4aed140eb881470964b869a03e13..c7941d7e3c2c7c7d9e8fdd2115d3f3618f82eba4 100644 GIT binary patch delta 389 zcmZoMXfc=|#>B!kF;Q%yo+2af#(>?7i$5?kG4f94VUnspxSN52frUYjA)O(Up(Hoo z#U&{xKM5$tVLM}Eio519M^yO~yz&JZhQZ1CxdlKy3=GTxAd;OSg&~!pm?4{?gdv}y zAgR2#0BXaIq=KCK%;FLQgKLaT%q*;I?ChNE-0ZQz8TsYGC5a`a#ZHMu(I8$(etu38 zjGdSimYG@}FCgNapI4HYnU`7w){vQ!3RDsko|%`DU+$D&nwL@x)*B3w;N;}sj2Doo zt~N3^)lo1uHm%iBsJ1jRGtf~mu{5f!<>U}m*0&Cd&(6us%kKg?oPmLn5kfQYLTMP) yJ-LNx50kFUB)qF;Q%yo+2a9#(>?7j69QhSft`sK44&AU}4Z>NN31oD9O!taY@R_ zPXdZ@+&=zY=ePPXM^yO~yz&JZhQZ1CxdlKy3=B*U7$!%t?qO2SoLs{ux7m#CBICw_ jYfPKjIruq%j@c~8@tt`xzlb9TNHHVO6`LbO)-VGA`1CD@ From 93155ffc2b5478bfa7f3bb17b4ed7f9cbfbbaa8c Mon Sep 17 00:00:00 2001 From: Fengyi Chen Date: Sat, 27 Jul 2024 14:21:30 +0800 Subject: [PATCH 4/6] Update README.md --- README.md | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 51 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 57e5456..0984d4a 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,51 @@ -# Pixel-Chat-App -A simple, server-deployable instant chat tool. +# 💬Pixel-Chat App + +一个简单、快速、开源的Python即时聊天系统,涵盖了多种聊天操作需求 + +### 🤩功能亮点 + +- 开箱即用,无需部署 +- 可将任意计算机、服务器上用作服务端使用,仅需一个 `Pixel Chat Desktop` 输入IP地址即可访问所有使用 `Pixel-Chat Server` 的聊天服务器 +- 内置防刷屏,自动封禁刷屏IP地址 +- 简单的黑名单IP管理 +- 简单方便的服务端命令,只需一个服务端即可掌控整个聊天服务器 +- 无需手动重置,因为不使用缓存,所以关闭重新打开自动清除数据 + +### ℹ️使用方法 + +###### 在服务器上运行服务端 + +1. 在用作服务端的服务器或计算机上安装[Python环境](https://python.org) +2. 在Release页面下载 `Pixel-Chat Server`,下载完成后运行 +3. VOILA! 现在邀请你的用户通过 `Pixel-Chat Client` 或 `Pixel-Chat Desktop` 访问服务器/计算机IP地址即可聊天 + +###### 访问您喜欢的聊天服务器 + +1. 在Release页面下载 `Pixel-Chat-Desktop`,下载完成后运行 +2. 输入您喜欢的聊天服务器IP +3. VOILA! 现在是聊天时间 + +###### 需要特殊/定制版本 + +请邮件联系[seventeen@ohdragonboi.cn](mailto:seventeen@ohdragonboi.cn)探讨您需要的内容,也许会需要您支付额外费用🤔 + +### 🎈贡献者列表 + +欢迎为本项目贡献一份你的力量,请参考Wiki中《贡献手册》章节为本项目提交PR或Issues + +> 排名不分先后,以下列表按时间顺序展示 + +| AVATAR | NAME | WORK | +| ------------------------------------------------------------ | ------------------------------------------------------- | --------------- | +| ![BunDragon's Github AVATAR](https://avatars.githubusercontent.com/u/120368045?s=400&u=ac60326a41a0d41faaf82ad25bcd143d85224791&v=4) | [磅豆龙(FrederickBun)](https://github.com/FrederickBun) | AUTHOR(Creator) | +| ![Rayminn's Github AVATAR](Fhttps:/avatars.githubusercontent.com/u/98998872%3Cbr/) | [Yiming Lei(Rayminn)](https://github.com/Rayminn) | AUTHOR(Editor) | + +### 📦特供版本与特殊版本使用者 + +如果你要选择定制你的 `Pixel-Chat Server`,下面的例子也许可以供你参考 + +| USER/ORGANIZATION | INFO | HOW TO THEY/THEIR USE | +| ------------------------ | ------------------------------------------------------------ | ---------------------------------------------------------- | +| 西南大学附中信息学竞赛生 | 本程序最初设计目的是为了此需求,后来开源,诞生了此项目。本文本中提到的 `Pixel-Chat Client` 就是最初由同学们编写的初代客户端,而 `Pixel-Chat Desktop` 是由[AlignPixel](https://github.com/AlignPixel)所改进的开源版本 | 用于刷题目时共享思路,一位同学运行服务端,全班同学可以使用 | + +### 🖼️屏幕截图 From 12691431f733029e92644cdad07cda53cad0827e Mon Sep 17 00:00:00 2001 From: Fengyi Chen Date: Sat, 27 Jul 2024 14:23:03 +0800 Subject: [PATCH 5/6] Update main.py --- server-client/main.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/server-client/main.py b/server-client/main.py index b3e8e44..ddcd555 100755 --- a/server-client/main.py +++ b/server-client/main.py @@ -44,11 +44,11 @@ class ChattingThread(threading.Thread): def run(self): try: - print('-> 连接来自于:', self.__caddr) + print('连接来自于:', self.__caddr) if self.__msg_handler.is_blacklisted(self.__caddr[0]): self.__handle_blacklisted() return - data = "欢迎你到来暑期聊天室!请遵守以下规则:\r\n"\ + data = "欢迎你来到由PixelChat驱动的聊天室!请遵守以下规则:\r\n"\ "1. 不要刷屏,否则将会被踢出\r\n"\ "2. 不要骂人,可以吐槽,但要适度\r\n"\ "3. 如有问题请联系服务器管理员\r\n"\ @@ -86,7 +86,7 @@ class ChattingThread(threading.Thread): def __handle_blacklisted(self): print('...黑塔安全拦截的用户:', self.__caddr) - data = '拒绝访问!请联系seventeen@ohdragonboi.cn' + data = '拒绝访问!请联系管理员处理' self.__cs.sendall(bytes(data, 'utf-8')) self.__cs.close() From 5a3363753f962b12978eeb06284adc6bee0e55b9 Mon Sep 17 00:00:00 2001 From: Fengyi Chen Date: Sat, 27 Jul 2024 14:39:30 +0800 Subject: [PATCH 6/6] Update README.md --- README.md | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 0984d4a..9200079 100644 --- a/README.md +++ b/README.md @@ -37,8 +37,8 @@ | AVATAR | NAME | WORK | | ------------------------------------------------------------ | ------------------------------------------------------- | --------------- | -| ![BunDragon's Github AVATAR](https://avatars.githubusercontent.com/u/120368045?s=400&u=ac60326a41a0d41faaf82ad25bcd143d85224791&v=4) | [磅豆龙(FrederickBun)](https://github.com/FrederickBun) | AUTHOR(Creator) | -| ![Rayminn's Github AVATAR](Fhttps:/avatars.githubusercontent.com/u/98998872%3Cbr/) | [Yiming Lei(Rayminn)](https://github.com/Rayminn) | AUTHOR(Editor) | +| BunDragon's Github AVATAR | [磅豆龙(FrederickBun)](https://github.com/FrederickBun) | AUTHOR(Creator) | +| Rayminn's Github AVATAR | [Yiming Lei(Rayminn)](https://github.com/Rayminn) | AUTHOR(Editor) | ### 📦特供版本与特殊版本使用者 @@ -49,3 +49,10 @@ | 西南大学附中信息学竞赛生 | 本程序最初设计目的是为了此需求,后来开源,诞生了此项目。本文本中提到的 `Pixel-Chat Client` 就是最初由同学们编写的初代客户端,而 `Pixel-Chat Desktop` 是由[AlignPixel](https://github.com/AlignPixel)所改进的开源版本 | 用于刷题目时共享思路,一位同学运行服务端,全班同学可以使用 | ### 🖼️屏幕截图 + +![总体截图](https://cdn.jsdelivr.net/gh/FrederickBun/upyun-rhimgcdn@img/upload/202407271438190.png) + +![客户端](https://cdn.jsdelivr.net/gh/FrederickBun/upyun-rhimgcdn@img/upload/202407271438066.png) + +![服务端](https://cdn.jsdelivr.net/gh/FrederickBun/upyun-rhimgcdn@img/upload/202407271438163.png) +