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中的ctime()方法使用教程
May 22 Python
利用python实现简单的循环购物车功能示例代码
Jul 05 Python
Python3 伪装浏览器的方法示例
Nov 23 Python
python jieba分词并统计词频后输出结果到Excel和txt文档方法
Feb 11 Python
Python2和Python3之间的str处理方式导致乱码的讲解
Jan 03 Python
Python3的高阶函数map,reduce,filter的示例详解
Jul 23 Python
Python Multiprocessing多进程 使用tqdm显示进度条的实现
Aug 13 Python
python使用pygame实现笑脸乒乓球弹珠球游戏
Nov 25 Python
python中从for循环延申到推导式的具体使用
Nov 29 Python
浅谈Python __init__.py的作用
Oct 28 Python
学会Python数据可视化必须尝试这7个库
Jun 16 Python
梳理总结Python开发中需要摒弃的18个坏习惯
Jan 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
php ss7.5的数据调用 (笔记)
2010/03/08 PHP
深入解析fsockopen与pfsockopen的区别
2013/07/05 PHP
用PHP写的一个冒泡排序法的函数简单实例
2016/05/26 PHP
php分页查询的简单实现代码
2017/03/14 PHP
禁止js文件缓存的代码
2010/04/09 Javascript
javascript oop开发滑动(slide)菜单控件
2010/08/25 Javascript
jQuery Ajax方法调用 Asp.Net WebService 的详细实例代码
2011/04/27 Javascript
jquery中插件实现自动添加用户的具体代码
2013/11/15 Javascript
javascript检测浏览器的缩放状态实现代码
2014/09/28 Javascript
JS+CSS相对定位实现的下拉菜单
2015/10/06 Javascript
基于javascript如何传递特殊字符
2015/11/30 Javascript
JS判断鼠标进入容器的方向与window.open新窗口被拦截的问题
2016/12/23 Javascript
基于node下的http小爬虫的示例代码
2018/01/11 Javascript
vue+axios+element ui 实现全局loading加载示例
2018/09/11 Javascript
VUE搭建手机商城心得和遇到的坑
2019/02/21 Javascript
使用Vue实现调用接口加载页面初始数据
2019/10/28 Javascript
解决Mint-ui 框架Popup和Datetime Picker组件滚动穿透的问题
2020/11/04 Javascript
对Python字符串中的换行符和制表符介绍
2018/05/03 Python
cmd运行python文件时对结果进行保存的方法
2018/05/16 Python
对python的文件内注释 help注释方法
2018/05/23 Python
tensorflow 恢复指定层与不同层指定不同学习率的方法
2018/07/26 Python
python用plt画图时,cmp设置方法
2018/12/13 Python
在Pytorch中计算自己模型的FLOPs方式
2019/12/30 Python
python如何使用代码运行助手
2020/07/03 Python
python入门教程之基本算术运算符
2020/11/13 Python
cosme官方海外旗舰店:日本最大化妆品和美容产品的综合口碑网站
2017/01/18 全球购物
internal修饰符起什么作用
2013/12/16 面试题
mysql有关权限的表都有哪几个
2015/04/22 面试题
最新大学生创业计划书写作攻略
2014/04/02 职场文书
法定代表人授权委托书
2014/04/04 职场文书
银行党的群众路线教育实践活动对照检查材料
2014/09/25 职场文书
工程项目经理岗位职责
2015/02/02 职场文书
2015大学生自我评价范文
2015/03/03 职场文书
答谢酒会主持词
2015/07/02 职场文书
公司管理制度范本
2015/08/03 职场文书
社区干部培训心得体会
2016/01/06 职场文书