发布时间:2019-09-19 08:04:45编辑:auto阅读(1593)
自学python一段时间,一直想弄个有意思的东西,所以就拿socket做一个聊天室,可以一对多,一对一全双工聊天。后续可能完善代码在鼓弄一个带gui界面的,比较有逼格。
服务端:
使用socketserver模块,多线程异步处理客户端消息,接受客户消息并转发 既服务端为一个中转站。
加入了 登陆 注册 多人聊天 一对一聊天 防止同时在线
客户端:
主线程连接服务端,两个子线程分别负责读写
sercer: # _*_ coding:utf-8 _*_ import SocketServer from time import ctime import threading, traceback import Queue from db import DB lock = threading.Lock() local_school = threading.local() class Handler(object): queue = [] db = DB() user_name = {} def __init__(self, sock): self.sock = sock self.input = [self.sock] # self.queue.append(self.sock) def recv(self): data = self.sock.recv(1024).strip() return data def send(self, data): self.sock.sendall(data) def stop(self): self.send('ByeBye') self.sock.close() self.queue.remove(self.sock) del self.user_name[local_school.user] def exit(self): self.sock.close() try: self.queue.remove(self.sock) del self.user_name[local_school.user] except ValueError: pass def broadcast(self, user, data): for sock in self.queue: sock.sendall('[%s] %s::%s' % (ctime(), user, data)) def one(self, user_sock, user, data): self.user_name[user_sock].sendall('--------------\n%s\n[%s]::(%s)\n---------------' % (ctime(), user, data)) def yiduiduo(self, user, data): time_data = ctime() for sock in [x for x in self.queue if x != self.sock]: sock.sendall('----------------\n%s\n[%s]::(%s)\n----------------' % (time_data, user, data)) def handler(self): funcdict = { 'login': self.login, 'registered': self.registered, } try: ###异常处理 当客户端异常断开连接或者正常断开连接:服务端处理异常 self.sock.send('请选择::login/registered/exit') data = self.recv() if data == 'exit': self.stop() # self.send('exit') elif data in funcdict: funcdict[data]() else: self.handler() except: if self.queue: self.exit() else: pass def login(self): self.send('输入账号密码 格式: user passwd /server') data = self.recv() if data == 'server': self.send('选择 exit/handler') data = self.recv() if data == 'exit': self.stop() elif data == 'handler': self.handler() else: self.login() user_data = data.split() if len(user_data) == 2: user = user_data[0] passwd = user_data[1] user_data = self.db.get_data() or {} data_scok = self.user_name.get(user) # 检测该用户是否在别处登陆 存在则登陆中 获得登陆的sock if data_scok: try: data_scok.sendall('账号在别处登陆,被迫下线') data_scok.close() self.queue.remove(data_scok) del self.user_name[local_school.user] except: ##异常处理 捕获此处所有异常不做处理 pass if user in user_data and user_data[user] == passwd: local_school.user = user self.send('欢迎加入聊天室') self.queue.append(self.sock) self.broadcast('systemctl', '[%s]加入聊天室\n' % user) self.user_name[user] = self.sock ##用户——sock 映射 self.send('选择:单(d)/多(s)') data = self.recv() if data == 's': self.Ltian() elif data == 'd': self.one_to_one() else: self.send('错误\n') self.handler() else: self.send('账号或密码不正确!\n') self.login() else: self.send('格式错误!\n') self.login() def registered(self): self.send('注册账号密码-格式 user passwd /server') data = self.recv() if data == 'server': self.send('选择 exit/handler') data = self.recv() if data == 'exit': self.stop() self.send('exit') else: self.handler() user_data = data.split() if len(user_data) == 2: user = user_data[0] passwd = user_data[1] db_data = self.db.get_data() or {} if user in db_data: self.send('用户已注册!') self.registered() else: db_data[user] = passwd local_school.user = user lock.acquire() # 添加线程锁,防止线程同时修改 数据文件 try: self.db.put_data(db_data) finally: lock.release() self.queue.append(self.sock) self.broadcast('system', '[%s]加入聊天室\n' % user) self.user_name[user] = self.sock self.send('选择:单人聊天(d)/多人聊天(s)\n') data = self.recv() if data == 's': self.Ltian() print self.queue elif data == 'd': self.one_to_one() else: self.send('错误!\n') self.handler() else: self.send('格式错误\n\n') self.registered() def Ltian(self, ): # 多人聊天 print self.queue print self.user_name self.send('kaishiliaotian') while True: data = self.recv() if data == 'exit': print 'queue1 ::%s' % self.queue self.stop() # self.send('关闭++++++++') print 'queue2 ::%s' % self.queue break self.yiduiduo(local_school.user, data) # 组播消息 def one_to_one(self): self.send('选择对象:to:user') user_data = self.recv()[3:] if user_data == local_school.user: self.one_to_one() if user_data in self.db.get_data(): if self.user_name.get(user_data) and self.user_name[user_data] in self.queue: self.send('kaishiliaotian') while True: data = self.recv() # if data is None: if data == 'server': self.send('选择:exit/Ltian(s)') data = self.recv() if data == 'exit': self.one(user_data, local_school.user, '已下线') self.stop() break elif data == 's': self.Ltian() elif not data == '' and self.user_name.get(user_data): # 判断 数据不为空 且用户状态在线否 self.one(user_data, local_school.user, data) else: self.send('用户不在线') self.one_to_one() else: self.send('用户不存在!\n') self.one_to_one() class MyServer(SocketServer.BaseRequestHandler): def handle(self): print self.client_address self.mysock = Handler(self.request) print self.mysock.queue self.mysock.handler() if __name__ == '__main__': host = '127.0.0.1' port = 9999 addr = (host, port) server = SocketServer.ThreadingTCPServer(addr, MyServer) server.request_queue_size = 4399 server.serve_forever() server.shutdown() client: # _*_ coding:utf-8 _*_ from socket import * import threading threads=[] class Client_Handler(object): def __init__(self, ipadr='127.0.0.1', port=9999): self.sock = socket(AF_INET, SOCK_STREAM) self.sock.connect((ipadr, port)) self.input=[self.sock] print self.input def send(self,data): self.sock.sendall(data) def recv(self): data = self.sock.recv(1024).strip() print data return data def write(self): while True: try: data=raw_input('>>>') if data=='exit': self.send('exit') self.sock.close() break self.send(data) except socket.error: #加入异常处理 当服务端断开sock连接时跳出while循环 break except: break def read(self): while True: try: self.recv() except socket.error: break except: break a1=Client_Handler() chat = threading.Thread(target=a1.write) threads.append(chat) chat = threading.Thread(target=a1.read) threads.append(chat) print threads for i in range(len(threads)): threads[i].start()
上一篇: Python写的ATM小程序
下一篇: python中的subprocess
47839
46385
37278
34728
29311
25969
24907
19947
19540
18019
5789°
6410°
5925°
5959°
7062°
5909°
5941°
6436°
6403°
7774°