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网络编程(十)的更多相关文章

  1. Python 网络编程(二)

    Python 网络编程 上一篇博客介绍了socket的基本概念以及实现了简单的TCP和UDP的客户端.服务器程序,本篇博客主要对socket编程进行更深入的讲解 一.简化版ssh实现 这是一个极其简单 ...

  2. Python 网络编程(一)

    Python 网络编程 socket通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄,应用程序通常通过"套接字"向网络发出请求或者应答网络请求. ...

  3. Python学习(22)python网络编程

    Python 网络编程 Python 提供了两个级别访问的网络服务.: 低级别的网络服务支持基本的 Socket,它提供了标准的 BSD Sockets API,可以访问底层操作系统Socket接口的 ...

  4. Day07 - Python 网络编程 Socket

    1. Python 网络编程 Python 提供了两个级别访问网络服务: 低级别的网络服务支持基本的 Socket,它提供了标准的 BSD Sockets API,可以访问底层操作系统Socket接口 ...

  5. python网络编程-01

    python网络编程 1.socket模块介绍 ①在网络编程中的一个基本组件就是套接字(socket),socket是两个程序之间的“信息通道”. ②套接字包括两个部分:服务器套接字.客户机套接字 ③ ...

  6. 《Python网络编程》学习笔记--使用谷歌地理编码API获取一个JSON文档

    Foundations of Python Network Programing,Third Edition <python网络编程>,本书中的代码可在Github上搜索fopnp下载 本 ...

  7. Python网络编程基础pdf

    Python网络编程基础(高清版)PDF 百度网盘 链接:https://pan.baidu.com/s/1VGwGtMSZbE0bSZe-MBl6qA 提取码:mert 复制这段内容后打开百度网盘手 ...

  8. python 网络编程(Socket)

    # from wsgiref.simple_server import make_server## def RunServer(environ,start_response):# start_resp ...

  9. python 网络编程 IO多路复用之epoll

    python网络编程——IO多路复用之epoll 1.内核EPOLL模型讲解     此部分参考http://blog.csdn.net/mango_song/article/details/4264 ...

  10. 自学Python之路-Python网络编程

    自学Python之路-Python网络编程 自学Python之路[第一回]:1.11.2 1.3

随机推荐

  1. ecilpse运行Servlet程序是找不到路径的原因

    当工作空间路径有空格时,空格会被转成%20,将导致路径无法识别,于是就找不到路径了.

  2. 牛客寒假算法基础集训营4 I题 Applese 的回文串

    链接:https://ac.nowcoder.com/acm/contest/330/I 来源:牛客网 自从 Applese 学会了字符串之后,精通各种字符串算法,比如--判断一个字符串是不是回文串. ...

  3. Faster-RCNN tensorflow 程序细节

    tf-faster-rcnn github:https://github.com/endernewton/tf-faster-rcnn backbone,例如vgg,conv层不改变feature大小 ...

  4. 查询Linux系统中glibc的版本

    编写一个简单的程序 #include <stdio.h> int main() { printf("Hello world\n"); ; } 编译 gcc test.c ...

  5. ab访问并发测试简要步骤

    工具: 1)ab -n 总访问次数  -c 并发用户数  目标url   查询某一个工具是哪个软件包安装的 rpm -qf 2)loadrunner 可视化 3)webbench 制作指定大小页面: ...

  6. websocket/dwebsocket 实现前后端的实时通信

    1.  用bottle框架,自己写一个服务端实现: 转载   :http://www.linuxyw.com/813.html 功能:用websocket技术,在运维工具的浏览器上实时显示远程服务器上 ...

  7. AtCoder Grand Contest 002 (AGC002) F - Leftmost Ball 动态规划 排列组合

    原文链接https://www.cnblogs.com/zhouzhendong/p/AGC002F.html 题目传送门 - AGC002F 题意 给定 $n,k$ ,表示有 $n\times k$ ...

  8. mysql 备份 恢复

    mysqldump -h127.0.0.1 -uroot -p123456 --databases dbname > e:/mysqlbak/dbname.dump不用新建数据库mysql -h ...

  9. 15行Python 仿百度搜索引擎

    开发工具:PyCharm 开发环境:python3.6 + flask + requests 开发流程: 1. 启动一个web服务 from flask import Flask app = Flas ...

  10. Maya Max python PySide集成 shiboken版本对应关系

    Maya_Max _python_PySide集成_shiboken版本对应关系 1.如何查看 Maya Max 集成的 Python版本: Maya:在 Maya 的安装目录下的 bin 文件夹中找 ...