使用Python实现多线程、多进程、异步IO的socket通信
多线程实现socket通信服务器端代码
import socket
import threading
class MyServer(object):
def __init__(self):
# 初始化socket
self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 设置服务器IP地址
host = '192.168.152.1'
# 设置服务器端口号
port = 4321
# 绑定IP地址和端口
self.server.bind((host, port))
# 设置最大监听数
self.server.listen(5)
# 设置一个字典,用来保存每一个客户端的连接和身份信息
self.socket_mapping = {}
# 设置接收的最大字节数
self.maxSize = 1024
def run(self):
while True:
socket, addr = self.server.accept()
# 发送信息,提示客户端已成功连接
socket.send('success!'.encode('utf-8'))
# 将客户端socket等信息存入字典
self.socket_mapping[socket] = addr
# 创建线程,负责获取键盘输入并发送给客户端
threading.Thread(target=self.send_to_client, args=(socket,)).start()
# 创建线程,负责接收客户端信息并转发给其他客户端
threading.Thread(target=self.recv_from_client, args=(socket,)).start()
def send_to_client(self, socket):
"""
获取键盘输入并发送给客户端
:param socket:
:return:
"""
while True:
info = input()
if info == "quit":
socket.close()
for socket in self.socket_mapping.keys():
socket.send(info.encode("utf-8"))
def recv_from_client(self, socket):
"""
接收客户端信息并转发给其他客户端
:param socket:
:return:
"""
while True:
recv_info = socket.recv(self.maxSize).decode('utf-8')
print('client{} say: '.format(self.socket_mapping[socket]), recv_info)
for i_socket in self.socket_mapping.keys():
if i_socket != socket:
i_socket.send(recv_info.encode("utf-8"))
my_server = MyServer()
my_server.run()
多进程实现socket通信服务器端代码
存在的问题:在与客户端连通后,需要服务器先发送两条消息,之后才能正常通信。
import os
import socket
import sys
from multiprocessing import Process, Manager
class MyServer(object):
def __init__(self):
# 初始化socket
self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 设置服务器IP地址
host = '192.168.152.1'
# 设置服务器端口号
port = 4321
# 绑定IP地址和端口
self.server.bind((host, port))
# 设置最大监听数
self.server.listen(5)
# 设置一个字典,用来保存每一个客户端的连接和身份信息
self.socket_mapping = Manager().dict()
# 设置接收的最大字节数
self.maxSize = 1024
# 进程锁
self.share_lock = Manager().Lock()
def run(self):
fn = sys.stdin.fileno()
while True:
socket, addr = self.server.accept()
# 发送信息,提示客户端已成功连接
socket.send('success!'.encode('utf-8'))
# 将客户端socket等信息存入字典
self.modify_mapping(self.socket_mapping, addr, socket, self.share_lock)
# 创建进程,负责获取键盘输入并发送给客户端
Process(target=self.send_to_client, args=(addr, fn)).start()
# 创建进程,负责接收客户端信息并转发给其他客户端
Process(target=self.recv_from_client, args=(addr,)).start()
def send_to_client(self, addr, fn):
"""
获取键盘输入并发送给客户端
:param addr:
:return:
"""
sys.stdin = os.fdopen(fn)
while True:
info = sys.stdin.readline()
if info == "quit":
self.socket_mapping[addr].close()
for socket in self.socket_mapping.values():
socket.send(info.encode("utf-8"))
def recv_from_client(self, addr):
"""
接收客户端信息并转发给其他客户端
:param addr:
:return:
"""
while True:
recv_info = self.socket_mapping.get(addr).recv(self.maxSize).decode('utf-8')
print('client{} say: '.format(addr), recv_info)
for i_addr in self.socket_mapping.keys():
if i_addr != addr:
self.socket_mapping.get(i_addr).send(recv_info.encode("utf-8"))
@staticmethod
def modify_mapping(share_var, share_key, share_value, share_lock):
# 获取锁
share_lock.acquire()
# 修改数据
share_var[share_key] = share_value
# 释放锁
share_lock.release()
if __name__ == "__main__":
my_server = MyServer()
my_server.run()
异步IO实现socket通信服务器端代码
存在的问题:通信时需要相互发送几次消息后,各自才会收到之前的消息并打印。
import socket
import asyncio
import select
class MyServer(object):
def __init__(self):
# 初始化socket
self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 设置服务器IP地址
host = '192.168.152.1'
# 设置服务器端口号
port = 4321
# 绑定IP地址和端口
self.server.bind((host, port))
# 设置最大监听数
self.server.listen(5)
# 设置一个字典,用来保存每一个客户端的连接和身份信息
self.socket_mapping = {self.server: None} # 这里存入self.server是为了充当select.select参数
# 设置接收的最大字节数
self.maxSize = 1024
# 进入事件循环
self.loop = asyncio.get_event_loop()
def run(self):
while True:
# select监听请求对象
rret, _, _ = select.select(self.socket_mapping.keys(), [], [])
for r_socket in rret:
if r_socket is self.server:
socket, addr = r_socket.accept()
# 发送信息,提示客户端已成功连接
socket.send('success!'.encode('utf-8'))
# 将客户端socket等信息存入字典
self.socket_mapping[socket] = addr
else:
task = [self.send_to_client(r_socket), self.recv_from_client(r_socket)]
self.loop.run_until_complete(asyncio.gather(*task))
async def send_to_client(self, socket):
"""
获取键盘输入并发送给客户端
:param socket:
:return:
"""
info = input()
if info == "quit":
socket.close()
for socket in self.socket_mapping.keys():
if socket != self.server:
socket.send(info.encode("utf-8"))
async def recv_from_client(self, socket):
"""
接收客户端信息并转发给其他客户端
:param socket:
:return:
"""
recv_info = socket.recv(self.maxSize).decode('utf-8')
print('client{} say: '.format(self.socket_mapping[socket]), recv_info)
for i_socket in self.socket_mapping.keys():
if i_socket != socket and i_socket != self.server:
i_socket.send(recv_info.encode("utf-8"))
my_server = MyServer()
my_server.run()
客户端代码(使用多线程)
import socket
import threading
class MyClient(object):
def __init__(self):
# 初始化socket
self.client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 设置服务器IP地址
self.host = '192.168.152.1'
# 设置服务器端口号
self.port = 4321
# 设置接收的最大字节数
self.max_size = 1024
def run(self):
# 与服务器建立连接
self.client.connect((self.host, self.port))
# 创建线程,负责获取键盘输入并发送给服务器
threading.Thread(target=self.sned_to_server).start()
# 创建线程,接收服务器信息
threading.Thread(target=self.recv_from_server).start()
def sned_to_server(self):
"""
获取键盘输入并发送给服务器
"""
while True:
send_msg = input()
self.client.send(send_msg.encode('utf-8'))
if send_msg == 'quit':
break
self.client.close()
def recv_from_server(self):
"""
接收服务器信息
"""
while True:
recv_info = self.client.recv(self.max_size).decode('utf-8')
print('server{} say: '.format((self.host, self.port)), recv_info)
my_client = MyClient()
my_client.run()
使用Python实现多线程、多进程、异步IO的socket通信的更多相关文章
- Python学习——多线程,异步IO,生成器,协程
Python的语法是简洁的,也是难理解的. 比如yield关键字: def fun(): for i in range(5): print('test') x = yield i print('goo ...
- 多线程/多进程/异步IO
SOCK_STREAM :TCPSOCK_Dgram :UDP family=AF_INET: 服务器之间的通信AF_INET6: 服务器之间的通信AF_UNIX: Unix不同进程间的通信 永远遵循 ...
- Python之路,Day10 - 异步IO\数据库\队列\缓存
Python之路,Day9 - 异步IO\数据库\队列\缓存 本节内容 Gevent协程 Select\Poll\Epoll异步IO与事件驱动 Python连接Mysql数据库操作 RabbitM ...
- Day10 - Python协程、异步IO、redis缓存、rabbitMQ队列
Python之路,Day9 - 异步IO\数据库\队列\缓存 本节内容 Gevent协程 Select\Poll\Epoll异步IO与事件驱动 Python连接Mysql数据库操作 RabbitM ...
- 从Nginx的Web请求处理机制中剖析多进程、多线程、异步IO
Nginx服务器web请求处理机制 从设计架构来说,Nginx服务器是与众不同的.不同之处一方面体现在它的模块化设计,另一方面,也是最重要的一方面,体现在它对客户端请求的处理机制上. Web服务器和客 ...
- python中同步、多线程、异步IO、多线程对IO密集型的影响
目录 1.常见并发类型 2.同步版本 3.多线程 4.异步IO 5.多进程 6.总结 1.常见并发类型 I/ O密集型: 蓝色框表示程序执行工作的时间,红色框表示等待I/O操作完成的时间.此图没有按比 ...
- Python协程、异步IO
本节内容 Gevent协程 Select\Poll\Epoll异步IO与事件驱动 Python连接Mysql数据库操作 RabbitMQ队列 Redis\Memcached缓存 Paramiko SS ...
- Python高级编程和异步IO并发编程
第1章 课程简介介绍如何配置系统的开发环境以及如何加入github私人仓库获取最新源码. 1-1 导学 试看 1-2 开发环境配置 1-3 资源获取方式第2章 python中一切皆对象本章节首先对比静 ...
- 【Python之路】异步IO
线程:CPU基本执行单元,可以与同属一个进程的其他线程共享资源,线程是属于进程的. 进程:资源单元,进程一般由程序.数据集.进程控制块三部分组成.一个进程默认有一个主线程, GIL:用于在进程中对所有 ...
- python 多协程异步IO爬取网页加速3倍。
from urllib import request import gevent,time from gevent import monkey#该模块让当前程序所有io操作单独标记,进行异步操作. m ...
随机推荐
- Exchange 2019数据库切换
最近在测试Exchange 2019的一些安装步骤.在测试到DAG的数据库切换的时候遇到了一些问题.An Active Manager operation failed. Error: The dat ...
- 【Tool】Idea快捷键
Windows Ctrl + F12: 查找当前类中的方法 Ctrl + N: 查找类 Ctrl + Alt + H: 查看方法调用关系 Ctrl + H: 查看类的继承关系 Alt + F7:查找类 ...
- Django 之必知必会三板斧
一.HttpResponse 在django.http 模块中定义了HttpResponse 对象的API,HttpRequest 对象由Django 自动创建,不调用模板,直接返回数据. 1 在 a ...
- 【项目实战】CNN手写识别
由于只需要修改之前基于ANN模型代码的模型设计部分所以篇幅较短,简单的加点注释给自己查看即可 视频链接:https://www.bilibili.com/video/BV1Y7411d7Ys?p=10 ...
- Logstash & 索引生命周期管理(ILM)
Grok语法 Grok是通过模式匹配的方式来识别日志中的数据,可以把Grok插件简单理解为升级版本的正则表达式.它拥有更多的模式,默认,Logstash拥有120个模式.如果这些模式不满足我们解析日志 ...
- [题解] Atcoder Beginner Contest ABC 270 G Ex 题解
点我看题 G - Sequence in mod P 稍微观察一下就会发现,进行x次操作后的结果是\(A^xS+(1+\cdots +A^{x-1})B\).如果没有右边那一坨关于B的东西,那我们要求 ...
- Java(15)Object类
前言 Object类是Java中所有类的始祖,在Java中每个类都扩展了Object.如果没有明确地指出超类,Object就被认为是这个类的超类.由于在Java中每个类都是由Object类扩展而来的, ...
- 8.RabbitMQ系列之RPC
1. RPC Remote Procedure Call:远程过程调用,一次远程过程调用的流程即客户端发送一个请求到服务端,服务端根据请求信息进行处理后返回响应信息,客户端收到响应信息后结束 2. C ...
- laravel 报错 AUTH` failed: ERR Client sent AUTH, but no password is set
明明没有设置redis密码.访问时候却报错 在代码里面的databases.php 改成这样就可以了.predis新版也会有取不到passwor的时候.改成我截图那样也可以.他默认取的是default ...
- 分享个好东西 - 两行前端代码搞定bilibili链接转视频
只需要在您的要解析B站视频的页面的</body>前面加上下面两行代码即可,脚本会在客户端浏览器里解析container所匹配到的容器里的B站超链接 (如果不是外围有a标签的超链接只是纯粹的 ...