在我的《python高级编程和异步io编程》中我讲解了socket编程,这里贴一段用socket实现聊天室的功能的源码,因为最近工作比较忙,后期我会将这里的代码细节分析出来,目前先把代码贴上。大家自行研究运行一下。
server端:

  1. """
  2. server select
  3. """
  4. import sys
  5. import time
  6. import socket
  7. import select
  8. import logging
  9. from queue import Queue
  10. import queue
  11. g_select_timeout = 10
  12. class Server(object):
  13. def __init__(self, host='0.0.0.0', port=3333, timeout=2, client_nums=10):
  14. self.__host = host
  15. self.__port = port
  16. self.__timeout = timeout
  17. self.__client_nums = client_nums
  18. self.__buffer_size = 1024
  19. self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  20. self.server.setblocking(False)
  21. self.server.settimeout(self.__timeout)
  22. self.server.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1) # keepalive
  23. self.server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) # 端口复用
  24. server_host = (self.__host, self.__port)
  25. try:
  26. self.server.bind(server_host)
  27. self.server.listen(self.__client_nums)
  28. except:
  29. raise
  30. self.inputs = [self.server] # select 接收文件描述符列表
  31. self.outputs = [] # 输出文件描述符列表
  32. self.message_queues = {} # 消息队列
  33. self.client_info = {}
  34. def run(self):
  35. while True:
  36. readable, writable, exceptional = select.select(self.inputs, self.outputs, self.inputs, g_select_timeout)
  37. if not (readable or writable or exceptional):
  38. continue
  39. for s in readable:
  40. if s is self.server: # 是客户端连接
  41. connection, client_address = s.accept()
  42. # print "connection", connection
  43. print("%s connect." % str(client_address))
  44. connection.setblocking(0) # 非阻塞
  45. self.inputs.append(connection) # 客户端添加到inputs
  46. self.client_info[connection] = str(client_address)
  47. self.message_queues[connection] = Queue() # 每个客户端一个消息队列
  48. else: # 是client, 数据发送过来
  49. try:
  50. data = s.recv(self.__buffer_size)
  51. except:
  52. err_msg = "Client Error!"
  53. logging.error(err_msg)
  54. if data:
  55. # print data
  56. data = "%s %s say: %s" % (time.strftime("%Y-%m-%d %H:%M:%S"), self.client_info[s], data)
  57. self.message_queues[s].put(data) # 队列添加消息
  58. if s not in self.outputs: # 要回复消息
  59. self.outputs.append(s)
  60. else: # 客户端断开
  61. # Interpret empty result as closed connection
  62. print
  63. "Client:%s Close." % str(self.client_info[s])
  64. if s in self.outputs:
  65. self.outputs.remove(s)
  66. self.inputs.remove(s)
  67. s.close()delself.message_queues[s]delself.client_info[s]for s in writable:# outputs 有消息就要发出去了try:
  68. next_msg =self.message_queues[s].get_nowait()# 非阻塞获取except queue.Empty:
  69. err_msg ="Output Queue is Empty!"# g_logFd.writeFormatMsg(g_logFd.LEVEL_INFO, err_msg)self.outputs.remove(s)exceptExceptionas e:# 发送的时候客户端关闭了则会出现writable和readable同时有数据,会出现message_queues的keyerror
  70. err_msg ="Send Data Error! ErrMsg:%s"% str(e)
  71. logging.error(err_msg)if s inself.outputs:self.outputs.remove(s)else:for cli inself.client_info:# 发送给其他客户端if cli isnot s:try:
  72. cli.sendall(next_msg.encode("utf8"))exceptExceptionas e:# 发送失败就关掉
  73. err_msg ="Send Data to %s Error! ErrMsg:%s"%(str(self.client_info[cli]), str(e))
  74. logging.error(err_msg)print"Client: %s Close Error."% str(self.client_info[cli])if cli inself.inputs:self.inputs.remove(cli)
  75. cli.close()if cli inself.outputs:self.outputs.remove(s)if cli inself.message_queues:delself.message_queues[s]delself.client_info[cli]for s in exceptional:
  76. logging.error("Client:%s Close Error."% str(self.client_info[cli]))if s inself.inputs:self.inputs.remove(s)
  77. s.close()if s inself.outputs:self.outputs.remove(s)if s inself.message_queues:delself.message_queues[s]delself.client_info[s]if"__main__"== __name__:Server().run()

client端

  1. #!/usr/local/bin/python
  2. # *-* coding:utf-8 -*-
  3. """
  4. client.py
  5. """
  6. import sys
  7. import time
  8. import socket
  9. import threading
  10. class Client(object):
  11. def __init__(self, host, port=3333, timeout=1, reconnect=2):
  12. self.__host = host
  13. self.__port = port
  14. self.__timeout = timeout
  15. self.__buffer_size = 1024
  16. self.__flag = 1
  17. self.client = None
  18. self.__lock = threading.Lock()
  19. @property
  20. def flag(self):
  21. return self.__flag
  22. @flag.setter
  23. def flag(self, new_num):
  24. self.__flag = new_num
  25. def __connect(self):
  26. client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  27. # client.bind(('0.0.0.0', 12345,))
  28. client.setblocking(True)
  29. client.settimeout(self.__timeout)
  30. client.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) # 端口复用
  31. server_host = (self.__host, self.__port)
  32. try:
  33. client.connect(server_host)
  34. except:
  35. raise
  36. return client
  37. def send_msg(self):
  38. if not self.client:
  39. return
  40. while True:
  41. time.sleep(0.1)
  42. # data = raw_input()
  43. data = sys.stdin.readline().strip()
  44. if "exit" == data.lower():
  45. with self.__lock:
  46. self.flag = 0
  47. break
  48. self.client.sendall(data.encode("utf8"))
  49. return
  50. def recv_msg(self):
  51. if not self.client:
  52. return
  53. while True:
  54. data = None
  55. with self.__lock:
  56. if not self.flag:
  57. print('ByeBye~~')
  58. break
  59. try:
  60. data = self.client.recv(self.__buffer_size)
  61. except socket.timeout:
  62. continue
  63. except:
  64. raise
  65. if data:
  66. print("%s\n" % data)
  67. time.sleep(0.1)
  68. return
  69. def run(self):
  70. self.client = self.__connect()
  71. send_proc = threading.Thread(target=self.send_msg)
  72. recv_proc = threading.Thread(target=self.recv_msg)
  73. recv_proc.start()
  74. send_proc.start()
  75. recv_proc.join()
  76. send_proc.join()
  77. self.client.close()
  78. if "__main__" == __name__:
  79. Client('localhost').run()

运行方式:电动叉车公司

  1. 启动server
    python server.py

  2. 启动client1
    python client.py

  3. 启动client2
    python client.py

在client1的console中输入任何字符串,client2中立马就可以收到

python的多路复用实现聊天群的更多相关文章

  1. 怎么用python 3 开发钉钉群机器人

    前言 文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理. 作者:Python绿色通道 PS:如有需要Python学习资料的小伙伴可以加 ...

  2. Python——IO多路复用之select模块epoll方法

    Python——IO多路复用之select模块epoll方法 使用epoll方法实现IO多路复用,使用方法基本与poll方法一致,epoll效率要高于select和poll. .├── epoll_c ...

  3. Python——IO多路复用之select模块poll方法

    Python——IO多路复用之select模块poll方法 使用poll方法实现IO多路复用 .├── poll_client.py├── poll_server.py└── settings.py ...

  4. Python——IO多路复用之select模块select方法

    Python——IO多路复用之select模块select方法 使用select模块的select方法实现Python——IO多路复用 实现同时将终端输入的文本以及客户端传输的文本写入文本文件中: w ...

  5. python 连接 redis cluster 集群

    一. redis集群模式有多种, cluster模式只是其中的一种实现方式, 其原理请自行谷歌或者百度, 这里只举例如何使用Python操作 redis cluster 集群 二. python 连接 ...

  6. python连接redis哨兵集群

    一.redis集群模式有多种, 哨兵模式只是其中的一种实现方式, 其原理请自行谷歌或者百度 二.python 连接 redis 哨兵集群 1. 安装redis包 pip install redis 2 ...

  7. 利用python获取自己的qq群成员信息

    利用python获取自己的qq群成员信息! 首先说明一下需要使用的工具以及技术:python3 + selenium selenium安装方法:pip install selenium 前提:获取自己 ...

  8. 今天建了一个Python学习交流的QQ群,求喜欢python的一起来交流。

    版权归作者所有,任何形式转载请联系作者.作者:枫(来自豆瓣)来源:https://www.douban.com/note/666182545/ 现在学python的人越来越多了,我也开始学习了,大群里 ...

  9. python实现简单的聊天小程序

    概要 这是一个使用python实现一个简单的聊天室的功能,里面包含群聊,私聊两种聊天方式.实现的方式是使用套接字编程的一个使用TCP协议 c/s结构的聊天室 实现思路 x01 服务端的建立 首先,在服 ...

随机推荐

  1. Word中摘要和正文同时分栏后,正文跑到下一页,怎么办?或Word分栏后第一页明明有空位后面的文字却自动跳到第二页了,怎么办?

    问题1:Word中摘要和正文同时分栏后,正文跑到下一页,怎么办?或Word分栏后第一页明明有空位后面的文字却自动跳到第二页了,怎么办? 答:在word2010中,菜单栏中最左侧选“文件”->“选 ...

  2. 算法练习——最长公共子序列的问题(LCS)

    问题描述: 对于两个序列X和Y的公共子序列中,长度最长的那个,定义为X和Y的最长公共子序列.X  Y   各自字符串有顺序,但是不一定需要相邻. 最长公共子串(Longest Common Subst ...

  3. cloudstack agent host Alert 告警处理

    今天nagios告警: 172.17.9.76有Alert,看agent的日志有如下: (Agent-Handler-3:null) Connected to the server Lost conn ...

  4. Sublime Text2中的快捷键一览表(Sublime 键盘快捷键大全 )

    快捷键 功能 ctrl+shift+n 打开新Sublime ctrl+shift+w 关闭Sublime,关闭所有打开文件 ctrl+shift+t 重新打开最近关闭文件 ctrl+n 新建文件 c ...

  5. activiti基础环境搭建创建数据库表及策略

    博主使用为activiti5.22的版本. 1.创建maven工程. 2.在pom文件中引入所需要的包,如:activiti包.数据库包. 这是我引用的包: <dependencies> ...

  6. 能够让你装逼的10个Python小技巧

      列表推导式 你有一个list: bag = [1, 2, 3, 4, 5] 现在你想让所有元素翻倍,让它看起来是这个样子: [2, 4, 6, 8, 10] 大多初学者,根据之前语言的经验会大概这 ...

  7. 【10.21总结】一个渗透测试练习实例——发现未知的漏洞(Race condition)

    Write-up地址:Exploiting an unknown vulnerability 作者:Abhishek Bundela 这篇文章跟我之前看到的文章不太一样,作者是按照一个练习的方式简单描 ...

  8. [BZOJ4484][JSOI2015]最小表示[拓扑排序+bitset]

    题意 给你一个 \(n\) 个点 \(m\) 条边的 \(\rm DAG\) ,询问最多能够删除多少条边,使得图的连通性不变 \(n\leq 3\times 10^4\ ,m\leq 10^5\) . ...

  9. Python之面向对象的组合、多态、菱形问题、子类中重用父类的两种方式

    一.组合 ''' 1.什么是组合 组合就是一个类的对象具备某一个属性,该属性的值是指向另外一个类的对象 2.为何用组合 组合也是用来解决类与类直接代码冗余问题的 3.如何用组合 ''' # 继承减少代 ...

  10. 解决web翻转动画闪屏

    首先确保backface-visibility: hidden.这样做可以解决大部分闪屏的情况. 然后需要特别注意的是谷歌的浏览器,不管是桌面端还是移动端,在翻转的过程中在该元素上绘制其他元素也会导致 ...