python 全双工 socket聊天
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了python 全双工 socket聊天相关的知识,希望对你有一定的参考价值。
自学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()
本文出自 “13275081” 博客,请务必保留此出处http://13285081.blog.51cto.com/13275081/1964230
以上是关于python 全双工 socket聊天的主要内容,如果未能解决你的问题,请参考以下文章