├── README.md ├── client.py └── server.py /README.md: -------------------------------------------------------------------------------- 1 | Python聊天室代码 2 | ========== 3 | -------------------------------------------------------------------------------- /client.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # encoding: utf-8 3 | 4 | import wx 5 | import telnetlib 6 | from time import sleep 7 | import thread 8 | 9 | class LoginFrame(wx.Frame): 10 | """ 11 | 登录窗口 12 | """ 13 | 14 | def __init__(self, parent, id, title, size): 15 | '初始化,添加控件并绑定事件' 16 | wx.Frame.__init__(self, parent, id, title) 17 | self.SetSize(size) 18 | self.Center() 19 | self.serverAddressLabel = wx.StaticText(self, label = "Server Address", pos = (10, 50), size = (120, 25)) 20 | self.userNameLabel = wx.StaticText(self, label = "UserName", pos = (40, 100), size = (120, 25)) 21 | self.serverAddress = wx.TextCtrl(self, pos = (120, 47), size = (150, 25)) 22 | self.userName = wx.TextCtrl(self, pos = (120, 97), size = (150, 25)) 23 | self.loginButton = wx.Button(self, label = 'Login', pos = (80, 145), size = (130, 30)) 24 | self.loginButton.Bind(wx.EVT_BUTTON, self.login) 25 | self.Show() 26 | 27 | def login(self, event): 28 | '登录处理' 29 | try: 30 | serverAddress = self.serverAddress.GetLineText(0).split(':') 31 | con.open(serverAddress[0], port = int(serverAddress[1]), timeout = 10) 32 | response = con.read_some() 33 | if response != 'Connect Success': 34 | self.showDialog('Error', 'Connect Fail!', (95, 20)) 35 | return 36 | con.write('login ' + str(self.userName.GetLineText(0)) + '\n') 37 | response = con.read_some() 38 | if response == 'UserName Empty': 39 | self.showDialog('Error', 'UserName Empty!', (135, 20)) 40 | elif response == 'UserName Exist': 41 | self.showDialog('Error', 'UserName Exist!', (135, 20)) 42 | else: 43 | self.Close() 44 | ChatFrame(None, -2, title = 'ShiYanLou Chat Client', size = (500, 350)) 45 | except Exception: 46 | self.showDialog('Error', 'Connect Fail!', (95, 20)) 47 | 48 | def showDialog(self, title, content, size): 49 | '显示错误信息对话框' 50 | dialog = wx.Dialog(self, title = title, size = size) 51 | dialog.Center() 52 | wx.StaticText(dialog, label = content) 53 | dialog.ShowModal() 54 | 55 | class ChatFrame(wx.Frame): 56 | """ 57 | 聊天窗口 58 | """ 59 | 60 | def __init__(self, parent, id, title, size): 61 | '初始化,添加控件并绑定事件' 62 | wx.Frame.__init__(self, parent, id, title) 63 | self.SetSize(size) 64 | self.Center() 65 | self.chatFrame = wx.TextCtrl(self, pos = (5, 5), size = (490, 310), style = wx.TE_MULTILINE | wx.TE_READONLY) 66 | self.message = wx.TextCtrl(self, pos = (5, 320), size = (300, 25)) 67 | self.sendButton = wx.Button(self, label = "Send", pos = (310, 320), size = (58, 25)) 68 | self.usersButton = wx.Button(self, label = "Users", pos = (373, 320), size = (58, 25)) 69 | self.closeButton = wx.Button(self, label = "Close", pos = (436, 320), size = (58, 25)) 70 | self.sendButton.Bind(wx.EVT_BUTTON, self.send) 71 | self.usersButton.Bind(wx.EVT_BUTTON, self.lookUsers) 72 | self.closeButton.Bind(wx.EVT_BUTTON, self.close) 73 | thread.start_new_thread(self.receive, ()) 74 | self.Show() 75 | 76 | def send(self, event): 77 | '发送消息' 78 | message = str(self.message.GetLineText(0)).strip() 79 | if message != '': 80 | con.write('say ' + message + '\n') 81 | self.message.Clear() 82 | 83 | def lookUsers(self, event): 84 | '查看当前在线用户' 85 | con.write('look\n') 86 | 87 | def close(self, event): 88 | '关闭窗口' 89 | con.write('logout\n') 90 | con.close() 91 | self.Close() 92 | 93 | def receive(self): 94 | '接受服务器的消息' 95 | while True: 96 | sleep(0.6) 97 | result = con.read_very_eager() 98 | if result != '': 99 | self.chatFrame.AppendText(result) 100 | 101 | '程序运行' 102 | if __name__ == '__main__': 103 | app = wx.App() 104 | con = telnetlib.Telnet() 105 | LoginFrame(None, -1, title = "Login", size = (280, 200)) 106 | app.MainLoop() 107 | -------------------------------------------------------------------------------- /server.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # encoding: utf-8 3 | 4 | from asyncore import dispatcher 5 | from asynchat import async_chat 6 | import socket, asyncore 7 | 8 | PORT = 6666 #端口 9 | 10 | class EndSession(Exception): 11 | """ 12 | 自定义会话结束时的异常 13 | """ 14 | pass 15 | 16 | class CommandHandler: 17 | """ 18 | 命令处理类 19 | """ 20 | 21 | def unknown(self, session, cmd): 22 | '响应未知命令' 23 | session.push('Unknown command: %s\n' % cmd) 24 | 25 | def handle(self, session, line): 26 | '命令处理' 27 | if not line.strip(): 28 | return 29 | parts = line.split(' ', 1) 30 | cmd = parts[0] 31 | try: 32 | line = parts[1].strip() 33 | except IndexError: 34 | line = '' 35 | meth = getattr(self, 'do_' + cmd, None) 36 | try: 37 | meth(session, line) 38 | except TypeError: 39 | self.unknown(session, cmd) 40 | 41 | class Room(CommandHandler): 42 | """ 43 | 包含多个用户的环境,负责基本的命令处理和广播 44 | """ 45 | 46 | def __init__(self, server): 47 | self.server = server 48 | self.sessions = [] 49 | 50 | def add(self, session): 51 | '一个用户进入房间' 52 | self.sessions.append(session) 53 | 54 | def remove(self, session): 55 | '一个用户离开房间' 56 | self.sessions.remove(session) 57 | 58 | def broadcast(self, line): 59 | '向所有的用户发送指定消息' 60 | for session in self.sessions: 61 | session.push(line) 62 | 63 | def do_logout(self, session, line): 64 | '退出房间' 65 | raise EndSession 66 | 67 | class LoginRoom(Room): 68 | """ 69 | 刚登录的用户的房间 70 | """ 71 | 72 | def add(self, session): 73 | '用户连接成功的回应' 74 | Room.add(self, session) 75 | session.push('Connect Success') 76 | 77 | def do_login(self, session, line): 78 | '登录命令处理' 79 | name = line.strip() 80 | if not name: 81 | session.push('UserName Empty') 82 | elif name in self.server.users: 83 | session.push('UserName Exist') 84 | else: 85 | session.name = name 86 | session.enter(self.server.main_room) 87 | 88 | class ChatRoom(Room): 89 | """ 90 | 聊天用的房间 91 | """ 92 | 93 | def add(self, session): 94 | '广播新用户进入' 95 | session.push('Login Success') 96 | self.broadcast(session.name + ' has entered the room.\n') 97 | self.server.users[session.name] = session 98 | Room.add(self, session) 99 | 100 | def remove(self, session): 101 | '广播用户离开' 102 | Room.remove(self, session) 103 | self.broadcast(session.name + ' has left the room.\n') 104 | 105 | def do_say(self, session, line): 106 | '客户端发送消息' 107 | self.broadcast(session.name + ': ' + line + '\n') 108 | 109 | def do_look(self, session, line): 110 | '查看在线用户' 111 | session.push('Online Users:\n') 112 | for other in self.sessions: 113 | session.push(other.name + '\n') 114 | 115 | class LogoutRoom(Room): 116 | """ 117 | 用户退出时的房间 118 | """ 119 | 120 | def add(self, session): 121 | '从服务器中移除' 122 | try: 123 | del self.server.users[session.name] 124 | except KeyError: 125 | pass 126 | 127 | class ChatSession(async_chat): 128 | """ 129 | 负责和单用户通信 130 | """ 131 | 132 | def __init__(self, server, sock): 133 | async_chat.__init__(self, sock) 134 | self.server = server 135 | self.set_terminator('\n') 136 | self.data = [] 137 | self.name = None 138 | self.enter(LoginRoom(server)) 139 | 140 | def enter(self, room): 141 | '从当前房间移除自身,然后添加到指定房间' 142 | try: 143 | cur = self.room 144 | except AttributeError: 145 | pass 146 | else: 147 | cur.remove(self) 148 | self.room = room 149 | room.add(self) 150 | 151 | def collect_incoming_data(self, data): 152 | '接受客户端的数据' 153 | self.data.append(data) 154 | 155 | def found_terminator(self): 156 | '当客户端的一条数据结束时的处理' 157 | line = ''.join(self.data) 158 | self.data = [] 159 | try: 160 | self.room.handle(self, line) 161 | except EndSession: 162 | self.handle_close() 163 | 164 | def handle_close(self): 165 | async_chat.handle_close(self) 166 | self.enter(LogoutRoom(self.server)) 167 | 168 | class ChatServer(dispatcher): 169 | """ 170 | 聊天服务器 171 | """ 172 | 173 | def __init__(self, port): 174 | dispatcher.__init__(self) 175 | self.create_socket(socket.AF_INET, socket.SOCK_STREAM) 176 | self.set_reuse_addr() 177 | self.bind(('', port)) 178 | self.listen(5) 179 | self.users = {} 180 | self.main_room = ChatRoom(self) 181 | 182 | def handle_accept(self): 183 | conn, addr = self.accept() 184 | ChatSession(self, conn) 185 | 186 | if __name__ == '__main__': 187 | s = ChatServer(PORT) 188 | try: 189 | asyncore.loop() 190 | except KeyboardInterrupt: 191 | print 192 | --------------------------------------------------------------------------------