设为首页 收藏本站
查看: 1009|回复: 0

[经验分享] python 全双工 socket聊天

[复制链接]

尚未签到

发表于 2018-8-4 11:26:39 | 显示全部楼层 |阅读模式
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.start()

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-546419-1-1.html 上篇帖子: Eclipse+python开发环境配置 下篇帖子: Python开发小知识集(一)
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表