python网络编程(十)
select版-TCP服务器
1. select 原理
在多路复用的模型中,比较常用的有select模型和epoll模型。这两个都是系统接口,由操作系统提供。当然,Python的select模块进行了更高级的封装。
网络通信被Unix系统抽象为文件的读写,通常是一个设备,由设备驱动程序提供,驱动可以知道自身的数据是否可用。支持阻塞操作的设备驱动通常会实现一组自身的等待队列,如读/写等待队列用于支持上层(用户层)所需的block或non-block操作。设备的文件的资源如果可用(可读或者可写)则会通知进程,反之则会让进程睡眠,等到数据到来可用的时候,再唤醒进程。
这些设备的文件描述符被放在一个数组中,然后select调用的时候遍历这个数组,如果对于的文件描述符可读则会返回改文件描述符。当遍历结束之后,如果仍然没有一个可用设备文件描述符,select让用户进程则会睡眠,直到等待资源可用的时候在唤醒,遍历之前那个监视的数组。每次遍历都是依次进行判断的。
2. select 回显服务器
使用python的select模块很容易写出下面一个echo(回显)服务器:
- import select
- import socket
- import sys
- server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- server.bind(('', 7788))
- server.listen(5)
- inputs = [server, sys.stdin]
- running = True
- while True:
- # 调用 select 函数,阻塞等待
- readable, writeable, exceptional = select.select(inputs, [], [])
- # 数据抵达,循环
- for sock in readable:
- # 监听到有新的连接
- if sock == server:
- conn, addr = server.accept()
- # select 监听的socket
- inputs.append(conn)
- # 监听到键盘有输入
- elif sock == sys.stdin:
- cmd = sys.stdin.readline()
- running = False
- break
- # 有数据到达
- else:
- # 读取客户端连接发送的数据
- data = sock.recv(1024)
- if data:
- sock.send(data)
- else:
- # 移除select监听的socket
- inputs.remove(sock)
- sock.close()
- # 如果检测到用户输入敲击键盘,那么就退出
- if not running:
- break
- server.close()
另外一个服务器(包含writeList):
- #coding=utf-8
- import socket
- import Queue
- from select import select
- SERVER_IP = ('', 9999)
- # 保存客户端发送过来的消息,将消息放入队列中
- message_queue = {}
- input_list = []
- output_list = []
- if __name__ == "__main__":
- server = socket.socket()
- server.bind(SERVER_IP)
- server.listen(10)
- # 设置为非阻塞
- server.setblocking(False)
- # 初始化将服务端加入监听列表
- input_list.append(server)
- while True:
- # 开始 select 监听,对input_list中的服务端server进行监听
- stdinput, stdoutput, stderr = select(input_list, output_list, input_list)
- # 循环判断是否有客户端连接进来,当有客户端连接进来时select将触发
- for obj in stdinput:
- # 判断当前触发的是不是服务端对象, 当触发的对象是服务端对象时,说明有新客户端连接进来了
- if obj == server:
- # 接收客户端的连接, 获取客户端对象和客户端地址信息
- conn, addr = server.accept()
- print("Client %s connected! "%str(addr))
- # 将客户端对象也加入到监听的列表中, 当客户端发送消息时 select 将触发
- input_list.append(conn)
- # 为连接的客户端单独创建一个消息队列,用来保存客户端发送的消息
- message_queue[conn] = Queue.Queue()
- else:
- # 由于客户端连接进来时服务端接收客户端连接请求,将客户端加入到了监听列表中(input_list),客户端发送消息将触发
- # 所以判断是否是客户端对象触发
- try:
- recv_data = obj.recv(1024)
- # 客户端未断开
- if recv_data:
- print("received %s from client %s"%(recv_data, str(addr)))
- # 将收到的消息放入到各客户端的消息队列中
- message_queue[obj].put(recv_data)
- # 将回复操作放到output列表中,让select监听
- if obj not in output_list:
- output_list.append(obj)
- except ConnectionResetError:
- # 客户端断开连接了,将客户端的监听从input列表中移除
- input_list.remove(obj)
- # 移除客户端对象的消息队列
- del message_queue[obj]
- print("\n[input] Client %s disconnected"%str(addr))
- # 如果现在没有客户端请求,也没有客户端发送消息时,开始对发送消息列表进行处理,是否需要发送消息
- for sendobj in output_list:
- try:
- # 如果消息队列中有消息,从消息队列中获取要发送的消息
- if not message_queue[sendobj].empty():
- # 从该客户端对象的消息队列中获取要发送的消息
- send_data = message_queue[sendobj].get()
- sendobj.send(send_data)
- else:
- # 将监听移除等待下一次客户端发送消息
- output_list.remove(sendobj)
- except ConnectionResetError:
- # 客户端连接断开了
- del message_queue[sendobj]
- output_list.remove(sendobj)
- print("\n[output] Client %s disconnected"%str(addr))
总结
优点
select目前几乎在所有的平台上支持,其良好跨平台支持也是它的一个优点。
缺点
select的一个缺点在于单个进程能够监视的文件描述符的数量存在最大限制,在Linux上一般为1024,可以通过修改宏定义甚至重新编译内核的方式提升这一限制,但是这样也会造成效率的降低。
一般来说这个数目和系统内存关系很大,具体数目可以cat /proc/sys/fs/file-max察看。32位机默认是1024个。64位机默认是2048.
对socket进行扫描时是依次扫描的,即采用轮询的方法,效率较低。
当套接字比较多的时候,每次select()都要通过遍历FD_SETSIZE个Socket来完成调度,不管哪个Socket是活跃的,都遍历一遍。这会浪费很多CPU时间。
python网络编程(十)的更多相关文章
- Python 网络编程(二)
Python 网络编程 上一篇博客介绍了socket的基本概念以及实现了简单的TCP和UDP的客户端.服务器程序,本篇博客主要对socket编程进行更深入的讲解 一.简化版ssh实现 这是一个极其简单 ...
- Python 网络编程(一)
Python 网络编程 socket通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄,应用程序通常通过"套接字"向网络发出请求或者应答网络请求. ...
- Python学习(22)python网络编程
Python 网络编程 Python 提供了两个级别访问的网络服务.: 低级别的网络服务支持基本的 Socket,它提供了标准的 BSD Sockets API,可以访问底层操作系统Socket接口的 ...
- Day07 - Python 网络编程 Socket
1. Python 网络编程 Python 提供了两个级别访问网络服务: 低级别的网络服务支持基本的 Socket,它提供了标准的 BSD Sockets API,可以访问底层操作系统Socket接口 ...
- python网络编程-01
python网络编程 1.socket模块介绍 ①在网络编程中的一个基本组件就是套接字(socket),socket是两个程序之间的“信息通道”. ②套接字包括两个部分:服务器套接字.客户机套接字 ③ ...
- 《Python网络编程》学习笔记--使用谷歌地理编码API获取一个JSON文档
Foundations of Python Network Programing,Third Edition <python网络编程>,本书中的代码可在Github上搜索fopnp下载 本 ...
- Python网络编程基础pdf
Python网络编程基础(高清版)PDF 百度网盘 链接:https://pan.baidu.com/s/1VGwGtMSZbE0bSZe-MBl6qA 提取码:mert 复制这段内容后打开百度网盘手 ...
- python 网络编程(Socket)
# from wsgiref.simple_server import make_server## def RunServer(environ,start_response):# start_resp ...
- python 网络编程 IO多路复用之epoll
python网络编程——IO多路复用之epoll 1.内核EPOLL模型讲解 此部分参考http://blog.csdn.net/mango_song/article/details/4264 ...
- 自学Python之路-Python网络编程
自学Python之路-Python网络编程 自学Python之路[第一回]:1.11.2 1.3
随机推荐
- 支持向量机-SMO算法简化版
SMO:序列最小优化 SMO算法:将大优化问题分解为多个小优化问题来求解 SMO算法的目标是求出一系列的alpha和b,一旦求出这些alpha,就很容易计算出权重向量w,并得到分隔超平面 工作原理:每 ...
- LOCK TABLES 和 UNLOCK TABLES
MySQLdump的时LOCK TABLES 和 UNLOCK TABLES 在mysqldump后的数据中会发现有 LOCK TABLES tables_name WRITE;和结尾处有 UNLOC ...
- Caused by: java.lang.NumberFormatException: For input string: "18446744073709551615"
问题:Caused by: java.lang.NumberFormatException: For input string: "18446744073709551615" 原因 ...
- jdk1.8学习、jdk1.9学习、jdk10.0学习和总结
由于中文参考资料很少,参考链接: https://www.oschina.net/translate/109-new-features-in-jdk-10 http://chuansong.me/n/ ...
- nginx 限制并发访问及请求频率
0. 1.参考 [工作]Nginx限制IP并发连接数和请求数的研究 Module ngx_http_limit_conn_module Module ngx_http_limit_req_module ...
- python全栈开发day98-DRF
1.CBV源码流程 2.restful协议 1 所有的数据,不过是通过网络获取的还是操作(增删改查)的数据,都是资源,将一切数据视为资源是REST区别与其他架构风格的最本质属性 2 面向资源架构(RO ...
- Centos7X部署Zabbix监控
一:yum安装LAMP环境 zabbix-server端防火墙配置(可以选择iptables -F清空) iptables -A INPUT -m state --state NEW -m tcp - ...
- Javascript 中调参数的脚本onclick="select(this)" this 怎么解释
解释1. this,指当前的onclick所在的节点本身. 比如: <div onclick='select(this)"></div> 则当点击div时,this就 ...
- Loadbalancer
LoadBalancer 可以将来自客户端的请求分发到不同的服务器,通过将一系列的请求转发到不同的服务器可以提高服务器的性能,并可以自动地寻找最优的服务器转发请求,这样不仅提高了系统性能,同时达到了负 ...
- 055 kafka可靠性与高性能
一:可靠性 1. 二:高性能 1.