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

"""
server select
""" import sys
import time
import socket
import select
import logging
from queue import Queue
import queue g_select_timeout = 10 class Server(object):
def __init__(self, host='0.0.0.0', port=3333, timeout=2, client_nums=10):
self.__host = host
self.__port = port
self.__timeout = timeout
self.__client_nums = client_nums
self.__buffer_size = 1024 self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.server.setblocking(False)
self.server.settimeout(self.__timeout)
self.server.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1) # keepalive
self.server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) # 端口复用
server_host = (self.__host, self.__port)
try:
self.server.bind(server_host)
self.server.listen(self.__client_nums)
except:
raise self.inputs = [self.server] # select 接收文件描述符列表
self.outputs = [] # 输出文件描述符列表
self.message_queues = {} # 消息队列
self.client_info = {} def run(self):
while True:
readable, writable, exceptional = select.select(self.inputs, self.outputs, self.inputs, g_select_timeout)
if not (readable or writable or exceptional):
continue for s in readable:
if s is self.server: # 是客户端连接
connection, client_address = s.accept()
# print "connection", connection
print("%s connect." % str(client_address))
connection.setblocking(0) # 非阻塞
self.inputs.append(connection) # 客户端添加到inputs
self.client_info[connection] = str(client_address)
self.message_queues[connection] = Queue() # 每个客户端一个消息队列 else: # 是client, 数据发送过来
try:
data = s.recv(self.__buffer_size)
except:
err_msg = "Client Error!"
logging.error(err_msg)
if data:
# print data
data = "%s %s say: %s" % (time.strftime("%Y-%m-%d %H:%M:%S"), self.client_info[s], data)
self.message_queues[s].put(data) # 队列添加消息 if s not in self.outputs: # 要回复消息
self.outputs.append(s)
else: # 客户端断开
# Interpret empty result as closed connection
print
"Client:%s Close." % str(self.client_info[s])
if s in self.outputs:
self.outputs.remove(s)
self.inputs.remove(s)
s.close()delself.message_queues[s]delself.client_info[s]for s in writable:# outputs 有消息就要发出去了try:
next_msg =self.message_queues[s].get_nowait()# 非阻塞获取except queue.Empty:
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
err_msg ="Send Data Error! ErrMsg:%s"% str(e)
logging.error(err_msg)if s inself.outputs:self.outputs.remove(s)else:for cli inself.client_info:# 发送给其他客户端if cli isnot s:try:
cli.sendall(next_msg.encode("utf8"))exceptExceptionas e:# 发送失败就关掉
err_msg ="Send Data to %s Error! ErrMsg:%s"%(str(self.client_info[cli]), str(e))
logging.error(err_msg)print"Client: %s Close Error."% str(self.client_info[cli])if cli inself.inputs:self.inputs.remove(cli)
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:
logging.error("Client:%s Close Error."% str(self.client_info[cli]))if s inself.inputs:self.inputs.remove(s)
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端

#!/usr/local/bin/python
# *-* coding:utf-8 -*- """
client.py
""" import sys
import time
import socket
import threading class Client(object):
def __init__(self, host, port=3333, timeout=1, reconnect=2):
self.__host = host
self.__port = port
self.__timeout = timeout
self.__buffer_size = 1024
self.__flag = 1
self.client = None
self.__lock = threading.Lock() @property
def flag(self):
return self.__flag @flag.setter
def flag(self, new_num):
self.__flag = new_num def __connect(self):
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# client.bind(('0.0.0.0', 12345,))
client.setblocking(True)
client.settimeout(self.__timeout)
client.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) # 端口复用
server_host = (self.__host, self.__port)
try:
client.connect(server_host)
except:
raise
return client def send_msg(self):
if not self.client:
return
while True:
time.sleep(0.1)
# data = raw_input()
data = sys.stdin.readline().strip()
if "exit" == data.lower():
with self.__lock:
self.flag = 0
break
self.client.sendall(data.encode("utf8"))
return def recv_msg(self):
if not self.client:
return
while True:
data = None
with self.__lock:
if not self.flag:
print('ByeBye~~')
break
try:
data = self.client.recv(self.__buffer_size)
except socket.timeout:
continue
except:
raise
if data:
print("%s\n" % data)
time.sleep(0.1)
return def run(self):
self.client = self.__connect()
send_proc = threading.Thread(target=self.send_msg)
recv_proc = threading.Thread(target=self.recv_msg)
recv_proc.start()
send_proc.start()
recv_proc.join()
send_proc.join()
self.client.close() if "__main__" == __name__:
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. select、poll 和epoll区别

    阻塞 I/O(blocking IO) 当用户进程调用了recvfrom这个系统调用,kernel就开始了IO的第一个阶段:准备数据(对于网络IO来说,很多时候数据在一开始还没有到达.比如,还没有收到 ...

  2. Oracle 表单的创建

    1.-- 连接 conn hu/aaa; -- 创建表空间 Create tablespace computer2005 nologging datafile 'd:/Oracle/product/1 ...

  3. VMware 虚拟机安装

    虚拟机下载 VMware官网地址:https://www.vmware.com/ 进行官网后,点击左边的下载图标,然后 作系统选择合适的产品,在这里以Windows系统为例,点击转至下载,如下图所示. ...

  4. 如何解析json字符串及返回json数据到前端

    前言:最近需要实现的任务是:写若干个接口,并且接口中的请求数据是json格式,然后按照请求参数读取前端提前整理好的json数据,并且将json数据返回到服务器端. 主要的工具:Gson  2.8.2 ...

  5. P2196 挖地雷

    题目背景 NOIp1996提高组第三题 题目描述 在一个地图上有N个地窖(N<=20),每个地窖中埋有一定数量的地雷.同时,给出地窖之间的连接路径.当地窖及其连接的数据给出之后,某人可以从任一处 ...

  6. 4.使用Jackson将Json数据转换成实体数据

    Jar下载地址:http://jackson.codehaus.org/ 注意: 一.类中的属性名称一定要和Json数据的属性名称一致(大写和小写敏感),类之间的嵌套关系也应该和Json数据的嵌套关系 ...

  7. 【git3】git+Gogs+webStorm的使用

    Gogs:相比gitlab更轻量级,基于golang的搭建自助 Git 服务.使用Gogs轻松搭建可能比GitLab更好用的Git服务平台. 参考资料:http://blog.csdn.net/u01 ...

  8. Linux中定时删除超过指定大小的文件夹

    背景: 开发环境总是动不动就没有空间了, 大部分都是debug日志.所以有必要在日志很疯狂的时候,删除不必要的日志. 思路:一. 书写删除日志文件脚本: 定时任务执行.  但是有时候的日志是需要保存用 ...

  9. 四层and七层负载均衡

    四层负载/七层负载 在常规运维工作中,经常会运用到负载均衡服务.负载均衡分为四层负载和七层负载,那么这两者之间有什么不同? 废话不多说,详解如下: 1.    什么是负载均衡 1)负载均衡(Load ...

  10. PHP核心技术——面向对象

    类与对象: 类的定义与实例化. //定义类 class person{ public $name; public $gender; public function say(){ echo $this- ...