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 巧用正则寻找字符串中的特定字符的位置方法
May 02 Python
解决python字典对值(值为列表)赋值出现重复的问题
Jan 20 Python
详解python中init方法和随机数方法
Mar 13 Python
TensorFlow卷积神经网络之使用训练好的模型识别猫狗图片
Mar 14 Python
ERLANG和PYTHON互通实现过程详解
Jul 05 Python
python实现简单图书管理系统
Nov 22 Python
Python While循环语句实例演示及原理解析
Jan 03 Python
django实现后台显示媒体文件
Apr 07 Python
Python Tkinter图形工具使用方法及实例解析
Jun 15 Python
Django返回HTML文件的实现方法
Sep 17 Python
Django缓存Cache使用详解
Nov 30 Python
Python实现Word文档转换Markdown的示例
Dec 22 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
JavaScript实现滚动栏效果的方法
2015/04/27 PHP
PHP中phar包的使用教程
2017/06/14 PHP
php工具型代码之印章抠图
2018/07/18 PHP
基于Jquery的将DropDownlist的选中值赋给label的实现代码
2011/05/06 Javascript
js前台判断开始时间是否小于结束时间
2012/02/23 Javascript
jquery fancybox ie6不显示关闭按钮的解决办法
2013/12/25 Javascript
jquery原创弹出层折叠效果点击折叠弹出一个层
2014/03/12 Javascript
使用JavaScript+canvas实现图片裁剪
2015/01/30 Javascript
微信小程序 textarea 详解及简单使用方法
2016/12/05 Javascript
详解前端自动化工具gulp自动添加版本号
2016/12/20 Javascript
浅谈vuepress 踩坑记
2018/04/18 Javascript
Vue中插入HTML代码的方法
2018/09/21 Javascript
微信小程序代码上传、审核发布小程序
2019/05/18 Javascript
vue实现短信验证码登录功能(流程详解)
2019/12/10 Javascript
基于aotu.js实现微信自动添加通讯录中的联系人功能
2020/05/28 Javascript
Vue实现购物小球抛物线的方法实例
2020/11/22 Vue.js
[57:53]DOTA2上海特级锦标赛主赛事日 - 2 败者组第二轮#3OG VS VP
2016/03/03 DOTA
[48:47]VGJ.S vs NB 2018国际邀请赛小组赛BO2 第一场 8.18
2018/08/19 DOTA
[01:23]2019完美世界全国高校联赛(春季赛)合肥全国总决赛
2019/06/10 DOTA
[54:28]EG vs OG 2019国际邀请赛小组赛 BO2 第一场 8.16
2019/08/18 DOTA
python网络编程实例简析
2014/09/26 Python
Python 内置函数complex详解
2016/10/23 Python
PyQt5图形界面播放音乐的实例
2019/06/17 Python
pandas实现to_sql将DataFrame保存到数据库中
2019/07/03 Python
Python中的相关分析correlation analysis的实现
2019/08/29 Python
香港永安旅游网:Wing On Travel
2017/04/10 全球购物
Kappa英国官方在线商店:服装和运动器材
2020/11/22 全球购物
2014两会学习心得:榜样精神伴我行
2014/03/17 职场文书
年终总结会主持词
2014/03/25 职场文书
农村党支部书记司法四风问题对照检查材料
2014/09/26 职场文书
在宿舍喝酒的检讨书
2014/09/28 职场文书
对照四风自我剖析材料
2014/10/07 职场文书
六查六看个人剖析材料
2014/10/14 职场文书
2016元旦晚会主持词
2015/07/01 职场文书
Python之matplotlib绘制折线图
2022/04/13 Python
vue项目打包后路由错误的解决方法
2022/04/13 Vue.js