博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Python 多人聊天工具 ( 多线程 )
阅读量:6826 次
发布时间:2019-06-26

本文共 5336 字,大约阅读时间需要 17 分钟。

程序实现:1、单或多客户端使用 telnet 登陆服务端 ( 可远程 ) 进行会话2、服务端实现登陆、注册、退出功能3、客户端发送的消息会被广播到已经登陆的其他用户界面4、连接到服务端后,可以执行相应的程序指令程序代码:https://coding.net/u/wangxiaoqiangs/p/pycode/git/tree/master/socket/GServerGServer.py#!/usr/bin/env python# coding: utf-8# author: Xiao Guaishouimport socketfrom db import DBfrom threading import currentThread, Threadclass HandlerThread(object):    queue = [] # sockect 队列    db = DB()    def __init__(self, sock):        self.sock = sock    def recv(self):        data = self.sock.recv(1024).strip() # 如果使用 while 接收数据时,会导致用户必须多敲一次回车键        return data    def send(self, data):        self.sock.sendall('\n[System]: %s\n' % data)    # 向队列中广播消息    def broadcast(self, user, data):        for sock in self.queue:            sock.sendall('\n[%s]: %s\n' % (user, data))    # 关闭客户端连接    def stop(self):        self.send('ByeBye!')        self.sock.close()        self.queue.remove(self.sock) # 关闭连接后,记得从队列中删除    # 程序入口    def handler(self):        funcdict = {                    'login': self.login,                    'register': self.register        }        try:            thname = currentThread().getName()            print('[%s] Got connection from %s' % (thname, self.sock.getpeername())) # 该程序中所有 print 的数据,将全部使用 loging 模块代替            self.send('请选择功能:login/register/exit')            data = self.recv()            if data == 'exit':                self.stop() # 其实这里应该单独使用 self.sock.close() 来关闭连接,因为这时队列中并没有该连接,不过有了下面的捕获就没有问题了 ^_^            elif data in funcdict:                return funcdict.get(data)()            else:                self.handler()        except: # 如果这里不捕获一下,就无法正常断开客户端连接            pass    # 处理用户登陆    def login(self):        self.send('Login... 请输入用户名密码,格式:User Password,输入 Server: 执行程序指令!')        user_data = self.recv()        # 程序内部指令        if user_data == 'Server:':            self.send('\n\tServer:use reged\t切换到注册页\n\tServer:exit\t\t退出系统')            user_data = self.recv()            if user_data == 'Server:use reged':                self.register()            elif user_data == 'Server:exit':                self.stop()            else:                self.send('输入错误...')        datalist = user_data.split()        # 判断用户输入,格式是否正确        if len(datalist) == 2:            user = datalist[0]            password = datalist[1]            db_data = self.db.get_data() or {}            if user in db_data and password == db_data.get(user):                self.queue.append(self.sock) # 有权限登陆系统者,连接被加入到队列中                self.send('欢迎加入聊天室,输入 Server: 获取功能方法!')                self.broadcast('System', '[%s] 加入聊天室!' % user)                self.chat_room(user)            else:                self.send('用户名、密码错误!')                self.login()        self.login()    def register(self):        self.send('Register... 请输入用户名密码,格式:User Password,输入 Server: 执行程序指令!')        user_data = self.recv()        if user_data == 'Server:':            self.send('\n\tServer:use login\t切换到注册页\n\tServer:exit\t\t退出系统')            user_data = self.recv()            if user_data == 'Server:login':                self.login()            elif user_data == 'Server:exit':                self.stop()            else:                self.send('输入错误...')        datalist = user_data.split()        if len(datalist) == 2:            user = datalist[0]            password = datalist[1]            db_data = self.db.get_data() or {}            if user in db_data:                self.send('该用户名已被注册!')                self.register()            else:                db_data[user] = password                self.db.put_data(db_data)                self.queue.append(self.sock)                self.broadcast('System', '新用户 [%s] 加入聊天室!' % user)                self.chat_room(user)        self.register()    def chat_room(self, user):        user_data = self.recv()        if user_data == 'Server:':            self.send('\n\tServer:logout\t退出聊天室')            user_data = self.recv()            if user_data == 'Server:logout':                self.stop()                return # 这里如果不加 return ,会将客户端执行的 Server: 指令也广播出去            else:                self.send('输入错误...')                self.chat_room(user)        else:            self.broadcast(user, user_data)            self.chat_room(user)# 为每连接创建线程def Startthread(sock, addr):    print('Received new client connection. %s:%s' % (addr[0], addr[1]))    th = HandlerThread(sock)    t = Thread(target=th.handler)    t.setDaemon(True)    t.start()# 启动服务def Server():    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)    s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)    s.bind(('0.0.0.0', 17170))    s.listen(1)    while True:        try:            sock, addr = s.accept()        except KeyboardInterrupt:            exit('\nByeBye!')        Startthread(sock, addr)    s.close()if __name__ == '__main__':    Server()    db.py# coding: utf-8import json# 创建一个类,代替数据库class DB(object):    def __init__(self, path='Storage.db'):        self.path = path    def get_data(self, data=None):        try:            with open(self.path) as f:                data = json.load(f)        except IOError as e:            return data # 首次取数据时,由于文件不存在或没数据,将返回默认值 None        finally:            return data    def put_data(self, data):        with open(self.path, 'w') as f:            json.dump(data, f)

转载于:https://www.cnblogs.com/wangxiaoqiangs/p/5630418.html

你可能感兴趣的文章
模块的查找顺序
查看>>
wpf中ListBox的选中项与ComboBox间的绑定
查看>>
web前台传参到后台出现错误
查看>>
数据库的备份和导入
查看>>
Oracle trunc()函数的用法
查看>>
col-md-*和col-sm-*
查看>>
前端开发大众手册(包括工具、网址、经验等)
查看>>
IOC容器
查看>>
“利益相关者”课堂讨论电子版
查看>>
意见总结
查看>>
servlet增删改查
查看>>
php - 中文字符串分割
查看>>
图解HTTP
查看>>
HTML - form (转)
查看>>
浅析C#深拷贝与浅拷贝 (转)
查看>>
3226. [SDOI2008]校门外的区间【线段树】
查看>>
如何解决jersey框架中以json格式返回数组,当数组中元素一个时json格式不对
查看>>
HDU 4898 The Revenge of the Princess’ Knight ( 2014 Multi-University Training Contest 4 )
查看>>
Kafka参数调优实战,看这篇文章就够了!
查看>>
delphi 把一个表的内容转到另一个表暂存时出错的解决方法。
查看>>