Python网络编程基于多线程实现多用户全双工聊天功能示例


Posted in Python onApril 10, 2018

本文实例讲述了Python网络编程基于多线程实现多用户全双工聊天功能。分享给大家供大家参考,具体如下:

在前面一篇《Python网络编程使用select实现socket全双工异步通信功能》中,我们实现了1对1的异步通信,在文章结尾,给出了多对多通信的思路。

既然说了,咱就动手试一试,本次用的是多线程来实现,正好练练手~

首先讲一下思路:

我们将服务器做为中转站来处理信息,一方面与客户端互动,另一方面进行消息转发。

大体思路确定下来后,需要确定一些通信规则:

1. 客户端与服务器建立连接后,需要输入用户名登入,若用户名已存在,将reuse反馈给用户,用户输出错误信息,退出

2. 用户输入正确的用户名后,即可进行通信了。如果未选择通信对象,则服务器会反馈信息,提示用户选择通信对象

3. 选择通信对象的方法为,输入to:username,如果所选择的对象不存在,反馈错误信息,重新输入

4.当正确选择通信对象后,双方建立连接,通过服务器中转信息进行通信

5.在通信中,若发送‘quit',则结束发送消息的线程,并指示服务器该用户准备登出,服务器删除该用户后,反馈消息给用户,用户结束接收消息的线程并退出

6.如果A正在与C通信,此时B向A发送信息,则A的通信窗口变为与B的通信窗口,即接收到B消息后,A发出的消息不再是给C,而是默认给B

实现代码:

#!/usr/bin/python
'test TCP server'
from socket import *
from time import ctime
import threading  #多线程模块
import re   #正则表达式模块
HOST = ''
PORT = 21567
BUFSIZ = 1024
ADDR = (HOST, PORT)
def Deal(sock, user):
  while True:
    data = sock.recv(BUFSIZ)  #接收用户的数据
    if data == 'quit':  #用户退出
      del clients[user]
      sock.send(data)
      sock.close()
      print '%s logout' %user
      break
    elif re.match('to:.+', data) is not None:  #选择通信对象
      data = data[3:]
      if clients.has_key(data):
        chatwith[sock] = clients[data]
        chatwith[clients[data]] = sock
      else:
        sock.send('the user %s is not exist' %data)
    else:
      if chatwith.has_key(sock):  #进行通信
        chatwith[sock].send("[%s] %s: %s" %(ctime(), user, data))
      else:
        sock.send('Please input the user who you want to chat with')
tcpSerSock = socket(AF_INET, SOCK_STREAM)
tcpSerSock.bind(ADDR)
tcpSerSock.listen(5)
clients = {}  #提供 用户名->socket 映射
chatwith = {}  #提供通信双方映射
while True:
  print 'waiting for connection...'
  tcpCliSock, addr = tcpSerSock.accept()
  print '...connected from:',addr
  username = tcpCliSock.recv(BUFSIZ)  #接收用户名
  print 'The username is:',username
  if clients.has_key(username):  #查找用户名
    tcpCliSock.send("Reuse")  #用户名已存在
    tcpCliSock.close()
  else:
    tcpCliSock.send("Welcome!")  #登入成功
    clients[username] = tcpCliSock
    chat = threading.Thread(target = Deal, args = (tcpCliSock,username))  #创建新线程进行处理
    chat.start()  #启动线程
tcpSerSock.close()
#!/usr/bin/python
'test tcp client'
from socket import *
import threading
HOST = 'localhost'
PORT = 21567
BUFSIZ = 1024
ADDR = (HOST, PORT)
threads = []
def Send(sock, test):  #发送消息
  while True:
    data = raw_input('>')
    tcpCliSock.send(data)
    if data == 'quit':
      break
def Recv(sock, test):   #接收消息
  while True:
    data = tcpCliSock.recv(BUFSIZ)
    if data == 'quit':
      sock.close()   #退出时关闭socket
      break
    print data
tcpCliSock = socket(AF_INET, SOCK_STREAM)
tcpCliSock.connect(ADDR)
print 'Please input your username:',
username = raw_input()
tcpCliSock.send(username)
data = tcpCliSock.recv(BUFSIZ)
if data == 'Reuse':
  print 'The username has been used!'
else:
  print 'Welcome!'
  chat = threading.Thread(target = Send, args = (tcpCliSock,None))  #创建发送信息线程
  threads.append(chat)
  chat = threading.Thread(target = Recv, args = (tcpCliSock,None))  #创建接收信息线程
  threads.append(chat)
  for i in range(len(threads)):  #启动线程
    threads[i].start()
  threads[0].join()  #在我们的设计中,send线程必然先于recv线程结束,所以此处只需要调用send的join,等待recv线程的结束。

当然,本程序还有许多不足之处,比如通信双方中A退出时,另一方B的通信列表中仍然又A,此时如果B再向已经登出的B发送消息,就会出错。博主比较懒,就不修复这个bug啦~

更多关于Python相关内容可查看本站专题:《Python Socket编程技巧总结》、《Python数据结构与算法教程》、《Python函数使用技巧总结》、《Python字符串操作技巧汇总》、《Python入门与进阶经典教程》及《Python文件与目录操作技巧汇总》

希望本文所述对大家Python程序设计有所帮助。

Python 相关文章推荐
Python批量提取PDF文件中文本的脚本
Mar 14 Python
python进行两个表格对比的方法
Jun 27 Python
Python 通过打码平台实现验证码的实现
May 13 Python
使用Python做垃圾分类的原理及实例代码附源码
Jul 02 Python
使用pyecharts生成Echarts网页的实例
Aug 12 Python
python使用pip安装SciPy、SymPy、matplotlib教程
Nov 20 Python
python shutil文件操作工具使用实例分析
Dec 25 Python
TensorFlow学习之分布式的TensorFlow运行环境
Feb 05 Python
python异步Web框架sanic的实现
Apr 27 Python
Django执行源生mysql语句实现过程解析
Nov 12 Python
python playwright 自动等待和断言详解
Nov 27 Python
基于Python实现将列表数据生成折线图
Mar 23 Python
Python比较2个时间大小的实现方法
Apr 10 #Python
Python文本处理之按行处理大文件的方法
Apr 09 #Python
Python网络编程使用select实现socket全双工异步通信功能示例
Apr 09 #Python
Python网络编程之TCP套接字简单用法示例
Apr 09 #Python
python3 读写文件换行符的方法
Apr 09 #Python
Python基于TCP实现会聊天的小机器人功能示例
Apr 09 #Python
Python生成任意范围任意精度的随机数方法
Apr 09 #Python
You might like
日本收入最高的漫画家:海贼王作者版税年收入高达8.45亿元
2020/03/04 日漫
JAVA/JSP学习系列之七
2006/10/09 PHP
如何使用PHP实现javascript的escape和unescape函数
2013/06/29 PHP
php 时间time与日期date之间的使用详解及区别
2016/11/07 PHP
Laravel框架实现修改登录和注册接口数据返回格式的方法
2018/08/17 PHP
php在linux环境中如何使用redis详解
2020/12/15 PHP
在UpdatePanel内jquery easyui效果失效的解决方法
2010/04/11 Javascript
事件绑定之小测试  onclick && addEventListener
2011/07/31 Javascript
jQuery页面滚动浮动层智能定位实例代码
2011/08/23 Javascript
jquery 日期控件datepicker属性详细解析
2013/11/08 Javascript
NodeJS的url截取模块url-extract的使用实例
2013/11/18 NodeJs
javascript 拷贝节点cloneNode()使用介绍
2014/04/03 Javascript
js中substring和substr的定义和用法
2014/05/05 Javascript
使用jQuery实现返回顶部
2015/01/26 Javascript
JavaScript每天定时更换皮肤样式的方法
2015/07/01 Javascript
详解js跨域原理以及2种解决方案
2015/12/09 Javascript
JQuery 在文档中查找指定name的元素并移除的实现方法
2016/05/19 Javascript
javascript基础知识
2016/06/07 Javascript
jQuery子元素过滤选择器用法示例
2016/09/09 Javascript
JS中substring与substr的用法
2016/11/16 Javascript
在js代码拼接dom对象到页面上去的模板总结(必看)
2017/02/14 Javascript
Angular5中提取公共组件之radio list的实例代码
2018/07/10 Javascript
vue使用rem实现 移动端屏幕适配
2018/09/26 Javascript
详解vue2.0 资源文件assets和static的区别
2018/11/27 Javascript
微信小程序实现的一键拨号功能示例
2019/04/24 Javascript
extjs图表绘制之条形图实现方法分析
2020/03/06 Javascript
基于python 处理中文路径的终极解决方法
2018/04/12 Python
Jmeter HTTPS接口测试证书导入过程图解
2020/07/22 Python
澳大利亚最好的在线时尚精品店:Princess Polly
2018/01/03 全球购物
abstract 可以和 virtual 一起使用吗?可以和 override 一起使用吗?
2012/10/15 面试题
什么是组件架构
2016/05/15 面试题
中专生学习生活的自我评价分享
2013/10/27 职场文书
班级团队活动方案
2014/08/14 职场文书
社保转移委托书范本
2014/10/08 职场文书
500字小学生检讨书
2015/02/19 职场文书
php实现自动生成验证码的实例讲解
2021/11/17 PHP