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制作爬虫并将抓取结果保存到excel中
Apr 06 Python
在Django中URL正则表达式匹配的方法
Dec 20 Python
详解python列表生成式和列表生成式器区别
Mar 27 Python
使用Flask-Cache缓存实现给Flask提速的方法详解
Jun 11 Python
python hough变换检测直线的实现方法
Jul 12 Python
如何通过python的fabric包完成代码上传部署
Jul 29 Python
python实现倒计时小工具
Jul 29 Python
python模块hashlib(加密服务)知识点讲解
Nov 25 Python
python列表推导式操作解析
Nov 26 Python
Python 中如何实现参数化测试的方法示例
Dec 10 Python
Python函数的定义方式与函数参数问题实例分析
Dec 26 Python
Anaconda使用IDLE的实现示例
Sep 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
在Ubuntu 14.04上部署 PHP 环境及 WordPress
2014/09/02 PHP
PHP中的类型提示(type hinting)功能介绍
2015/07/01 PHP
怎样搭建PHP开发环境
2015/07/28 PHP
详解PHP的Yii框架中的Controller控制器
2016/03/29 PHP
PHP实现对文件锁进行加锁、解锁操作的方法
2017/07/04 PHP
利用php + Laravel如何实现部署自动化详解
2017/10/11 PHP
javascript 匿名函数的理解(透彻版)
2010/01/28 Javascript
使用jQuery向asp.net Mvc传递复杂json数据-ModelBinder篇
2010/05/07 Javascript
js中判断控件是否存在
2010/08/25 Javascript
JQuery Highcharts 动态生成图表的方法
2013/11/15 Javascript
javascript 闭包详解
2015/07/02 Javascript
JS点击某个图标或按钮弹出文件选择框的实现代码
2016/09/27 Javascript
JS实现的简单轮播图运动效果示例
2016/12/22 Javascript
React组件的三种写法总结
2017/01/12 Javascript
小程序云函数调用API接口的方法
2019/05/17 Javascript
微信小程序授权登陆及每次检查是否授权实例代码
2019/09/18 Javascript
原生js实现下拉选项卡
2019/11/27 Javascript
node.js 使用 net 模块模拟 websocket 握手进行数据传递操作示例
2020/02/11 Javascript
JS表单验证插件之数据与逻辑分离操作实例分析【策略模式】
2020/05/01 Javascript
国内常用的js类库大全(CDN公共库)
2020/06/24 Javascript
python如何保证输入键入数字的方法
2019/08/23 Python
python多进程并行代码实例
2019/09/30 Python
基于python实现计算且附带进度条代码实例
2020/03/31 Python
Python-jenkins模块获取jobs的执行状态操作
2020/05/12 Python
Python中常用的os操作汇总
2020/11/05 Python
HTML5 Canvas实现文本对齐的方法总结
2016/03/24 HTML / CSS
Sneaker Studio捷克:购买运动鞋
2018/07/08 全球购物
美国领先的在线旅游网站:Orbitz
2018/11/05 全球购物
Pretty You London官网:英国拖鞋和睡衣品牌
2019/05/08 全球购物
工程造价专业大学生自荐信
2013/10/01 职场文书
写好求职信第一句话的技巧
2013/10/26 职场文书
征兵宣传标语
2014/06/20 职场文书
2015世界地球日活动总结
2015/02/09 职场文书
《索溪峪的野》教学反思
2016/02/19 职场文书
nginx安装以及配置的详细过程记录
2021/09/15 Servers
世界十大儿童漫画书排名,法国国宝漫画排第五,第二是轰动日本连环
2022/03/18 欧美动漫