在我的《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. Node.js 连接 MongoDB-7

    先安装模块: npm install --save mongodb 当然,首先你要打开mongodb服务端: mongod --bind_ip 127.0.0.1 创建数据库 要在 MongoDB 中 ...

  2. nmap 扫描端口 + iftop 实时监控流量

    sleep 1|telnet 127.0.0.1 223 nmap 127.0.0.1 -p 223 -PN   (对禁ping IP) iftop -P -n -B -B 按字节显示 -N 切换 端 ...

  3. http协议中的keeplive是做什么的?它的适应场景是什么?

    1.Http底层也是通过TCP传输的. 2.HTTP keep-alive Http是一个”请求-响应”协议,它的keep-alive主要是为了让多个http请求共享一个Tcp连接,以避免每个Http ...

  4. C#中的结构体与类的区别 (转载)

    经常听到有朋友在讨论C#中的结构与类有什么区别.正好这几日闲来无事,自己总结一下,希望大家指点. 1. 首先是语法定义上的区别啦,这个就不用多说了.定义类使用关键字class 定义结构使用关键字str ...

  5. CCF认证201712-2游戏

    问题描述 有n个小朋友围成一圈玩游戏,小朋友从1至n编号,2号小朋友坐在1号小朋友的顺时针方向,3号小朋友坐在2号小朋友的顺时针方向,……,1号小朋友坐在n号小朋友的顺时针方向. 游戏开始,从1号小朋 ...

  6. 笔记:long、longlong、int、float、NSString相互转换

    NSString *"; // 1.字符串转int int intString = [string intValue]; // 2.int转字符串 NSString *stringInt = ...

  7. better-scroll之吸顶效果巨坑挣扎中

    今天和大家分享下better-scroll这款移动端用来解决各种滚动需求的插件(目前已经支持PC) 关于其中的API大家可以去官网看下  这里就给大家介绍几种常用的以及需要注意的点是什么 首先说一下b ...

  8. 七、Delphi10.3读取JSON数组

    一.Delphi读取JSON数组是非常方便的,首先我们网上找一段JSON数据 { "error": 0, "status": "success&quo ...

  9. go语言实战笔记(二)

     码代码之前一定要安装go,哈哈哈哈,反正我只装goland然后写不了代码报错,卡在第一段代码哈哈哈哈哈哈 新建项目goproject 新建src文件夹 新建main文件夹 新建第一个go文件 开始写 ...

  10. 编写Dockerfiles

    指令 docker build通过Dockerfile制作镜像 docker build [PATH] [-f Dockerfile] 其中PATH不写,默认执行指令的当前目录,不要用 /,这样将导致 ...