参考:待csdn收藏服务恢复后添加,或者自行去找
可能的报错包含但不限于:
error: uncaptured python exception, closing channel <__main__.ChatSession connected 127.0.0.1:61630 at 0x108d2b640> (<class 'TypeError'>:argument should be integer or bytes-like object, not 'str' [/usr/local/Cellar/python@3.8/3.8.5/Frameworks/Python.framework/Versions/3.8/lib/python3.8/asyncore.py|read|83] [/usr/local/Cellar/python@3.8/3.8.5/Frameworks/Python.framework/Versions/3.8/lib/python3.8/asyncore.py|handle_read_event|420] [/usr/local/Cellar/python@3.8/3.8.5/Frameworks/Python.framework/Versions/3.8/lib/python3.8/asynchat.py|handle_read|161])
解决方法:
首先,python3中需要将类似 session.push(line+b'\r\n')的方法,字符串前面全部加b
然后,将所有传数据的进行加密解密 self.data.append(data.decode('utf-8'))
检查修改完成后,如果还有报错,根据报错的位置去对应的地方修改便可
修改后可执行的python3版本代码如下
import asyncore
import socket
from asynchat import async_chat
from asyncore import dispatcher
PORT = 5005
NAME = 'TestChat'
class ChatSession(async_chat):
"""
一个负责处理服务器和单个用户间连接的类
"""
def __init__(self, server, sock):
## 标准的设置任务:
async_chat.__init__(self, sock)
self.server = server
self.set_terminator(b'\r\n')
self.data = []
# 问候用户:
self.push(b'Welcome to %s\r\n'%self.server.name.encode('utf-8'))
# self.push('Wlecome')
def collect_incoming_data(self, data):
self.data.append(data.decode('utf-8'))
def found_terminator(self):
line = ''.join(self.data)
self.data = []
# print(line)
self.server.broadcast(line.encode('utf-8'))
def handle_close(self):
async_chat.handle_close(self)
self.server.disconnect(self)
class ChatServer(dispatcher):
def __init__(self, port,name):
dispatcher.__init__(self)
self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
self.set_reuse_addr() # 重用原来的地址(具体地说是端口号),即便未妥善关 闭服务器亦如此。如果不调用set_reuse_addr,可能需要等待一段时间才能重启服务器
self.bind(('', port)) # ''代表localhost
self.listen(5)
self.name = name
self.sessions = []
def disconnect(self,session):
self.sessions.remove(session)
def broadcast(self,line):
for session in self.sessions:
session.push(line+b'\r\n')
def handle_accept(self):
conn, addr = self.accept()
self.sessions.append(ChatSession(self,conn))
if __name__ == "__main__":
s = ChatServer(PORT,NAME)
try:
asyncore.loop()
except KeyboardInterrupt:
print()
python3复杂版茶话会
# -*- coding: utf-8 -*-
# @Time : 2020/11/9 11:31 上午
# @Author : lixia
# @File : chartserver.py
# @desc:一个更复杂些的聊天服务器 python2版 https://blog.csdn.net/orangleliu/article/details/8837539
import asyncore
import socket
from asynchat import async_chat
from asyncore import dispatcher
# from pygments.formatters import other
PORT = 5005
NAME = 'TestChat'
class EndSession(Exception): pass
class CommandHandler:
"""
类似于标准库中cmd.Cmd的简单命令处理程序
"""
def unknown(self, session, cmd):
session.push(b'Unknown command:%s\r\n'%cmd.encode('utf-8'))
def handle(self, session, line):
'处理从指定会话收到的行'
if not line.strip(): return
# 提取命令:
parts = line.split(' ', 1)
print("parts:",parts)
cmd = parts[0]
print("cmd:",cmd)
try:
line = parts[1].strip()
except IndexError:
line = ''
meth = getattr(self, 'do_' + cmd, None)
try:
# 假定它是可调用的:
meth(session, line)
except TypeError as e:
print(e)
# 如果是不可调用的,就响应未知命令:
self.unknown(session, cmd)
class Room(CommandHandler):
"""
可能包含一个或多个用户(会话)的通用环境。它负责基本的命令处理和广播
"""
def __init__(self, server):
self.server = server
self.sessions = []
def add(self, session):
"""
'有会话(用户)进入聊天室'
:param session:
:return:
"""
self.sessions.append(session)
def remove(self, session):
"""
'有会话(用户)离开聊天室'
:param session:
:return:
"""
self.sessions.remove(session)
def broadcast(self, line):
"""将一行内容发送给聊天室内的所有会话"""
for session in self.sessions:
session.push(line)
def do_logout(self, session, line):
"""
响应命令logout
:param session:
:param line:
:return:
"""
raise EndSession
class LoginRoom(Room):
"""
为刚连接的用户准备的聊天室
"""
def add(self, session):
Room.add(self, session)
# 用户进入时,向他/她发出问候:
self.broadcast(b'Welocome to %s\r\n'%self.server.name.encode('utf-8'))
def unknown(self, session, cmd):
# 除login和logout外的所有命令都会
# 导致系统显示提示消息:
session.push(b'Please login \r\nUse "login <nick>"\r\n')
def do_login(self,session,line):
name = line.strip().encode('utf-8')
print(name)
print(self.server.users)
# 确保用户输入了用户名:
if not name:
session.push(b'Please enter a name\r\n')
# 确保用户名未被占用:
elif name in self.server.users:
session.push(b'The name "%s" is taken \r\n'%name)
session.push(b'Please try again \r\n')
else:
# 用户名没问题,因此将其存储到会话中并将用户移到主聊天室
session.name = name
session.enter(self.server.main_room)
class ChatRoom(Room):
"""
为多个用户相互聊天准备的聊天室
"""
def add(self,session):
# 告诉所有人有新用户进入:
self.broadcast(session.name+b' has entered the room\r\n')
self.server.users[session.name]=session
print(self.server.users)
# super().add(session)
Room.add(self,session)
def remove(self, session):
Room.remove(self,session)
self.broadcast(session.name+b' has left the room\r\n')
def do_say(self,session,line):
self.broadcast(session.name+":".encode('utf-8')+line.encode('utf-8') +b"\r\n")
def do_look(self,session,line):
'处理命令look,这个命令用于查看聊天室里都有谁'
session.push(b'The following are in this room:\r\n')
for other in self.sessions:
session.push(other.name+b"\r\n")
def do_who(self,session,line):
'处理命令who,这个命令用于查看谁已登录'
session.push(b'The following are logged in:\r\n')
for name in self.server.users:
session.push(name+b"\r\n")
class LogoutRoom(Room):
"""
为单个用户准备的聊天室,仅用于将用户名从服务器中删除
"""
def add(self,session):
# 将进入LogoutRoom的用户删除
try:
del self.server.users[session.name]
except KeyError:
pass
class ChatSession(async_chat):
"""
单个会话,负责与单个用户通信
"""
def __init__(self,server,sock):
super().__init__(sock)
self.server = server
self.set_terminator(b"\r\n")
self.data=[]
self.name = None
# 所有会话最初都位于LoginRoom中:
self.enter(LoginRoom(server))
def enter(self,room):
# 自己从当前聊天室离开,并进入下一个聊天室
try:
cur = self.room
except AttributeError:
pass
else:
cur.remove(self)
self.room = room
room.add(self)
def collect_incoming_data(self, data):
self.data.append(data.decode('utf-8'))
def found_terminator(self):
line = ''.join(self.data)
self.data=[]
try:
self.room.handle(self,line)
except EndSession:
self.handle_close()
def handle_close(self):
async_chat.handle_close(self)
self.enter(LogoutRoom(self.server))
class ChatServer(dispatcher):
"""
只有一个聊天室的聊天服务器
"""
def __init__(self,port,name):
super().__init__()
self.create_socket(socket.AF_INET,socket.SOCK_STREAM)
self.set_reuse_addr()
self.bind(('',port))
self.listen(5)
self.name = name
self.users={}
self.main_room=ChatRoom(self)
def handle_accept(self):
conn,addr = self.accept()
ChatSession(self,conn)
if __name__=="__main__":
s = ChatServer(PORT,NAME)
try:
asyncore.loop()
except KeyboardInterrupt:
print()
结果图: