概述

  目的:同一个线程同时处理多个IO请求。

  本文以python的select模块来实现socket编程中一个server同时处理多个client请求的问题。

  web框架tornado就是以此实现多客户端连接问题的。以下为select源码说明:

def select(rlist, wlist, xlist, timeout=None): # real signature unknown; restored from __doc__
"""
select(rlist, wlist, xlist[, timeout]) -> (rlist, wlist, xlist) Wait until one or more file descriptors are ready for some kind of I/O.
The first three arguments are sequences of file descriptors to be waited for:
rlist -- wait until ready for reading
wlist -- wait until ready for writing
xlist -- wait for an ``exceptional condition''
If only one kind of condition is required, pass [] for the other lists.
A file descriptor is either a socket or file object, or a small integer
gotten from a fileno() method call on one of those. The optional 4th argument specifies a timeout in seconds; it may be
a floating point number to specify fractions of seconds. If it is absent
or None, the call will never time out. The return value is a tuple of three lists corresponding to the first three
arguments; each contains the subset of the corresponding file descriptors
that are ready. *** IMPORTANT NOTICE ***
On Windows and OpenVMS, only sockets are supported; on Unix, all file
descriptors can be used.
"""
pass # classes

实例1

server端

#!/usr/bin/env python
#-*- coding:utf-8 -*-
import socket
import select
ss = socket.socket()
ss.bind(("localhost",8000))
ss.listen(5)
ss.setblocking(False) inputs = [ss]
while True:
rList,wList,e = select.select(inputs,[],[],2)
print "inputs:", inputs
print "resaults:", rList
for r in rList:
if r == ss:
con,addr = r.accept()
inputs.append(con)
else: try:
data = r.recv(1024)
except socket.error,e:
inputs.remove(r)
else:
r.send(data)

server

client端

#!/usr/bin/env python
#-*- coding:utf-8 -*-
import socket sc = socket.socket()
sc.connect(("localhost",8000))
while True:
data = raw_input("Input:")
sc.sendall(data)
print sc.recv(1024)
sc.close()

client

操作步骤

  1. 启动server
  2. 启动client,并输入:123
  3. 再次启动client,并输入:345

操作结果:

  • client1
Input:123
123
Input:
  • client2
Input:345
345
Input:
  • server端
#启动server,不启动client,select监听的句柄为:ss_70,无变化,select监听结果:resaults = []
inputs: [<socket._socketobject object at 0x0241FC70>]
resaults: []
#启动client,句柄ss_FC70连接了客户端,select将监听到的变化的句柄返回,rList=[ss_70]
inputs: [<socket._socketobject object at 0x0241FC70>]
resaults: [<socket._socketobject object at 0x0241FC70>]
#将ss.accept()得到的客户端句柄conn_A8追加至监听列表,inputs = [ss_70,conn_A8,],当client不发送请求时,select监听的inputs列表中的句柄没有发生变化,返回列表resaults=[]
inputs: [<socket._socketobject object at 0x0241FC70>, <socket._socketobject object at 0x0241FCA8>]
resaults: []
#client发送信息时,server端select监听的inputs列表中conn_A8句柄发生变化,select返回监听结果:rList = [conn_A8]
inputs: [<socket._socketobject object at 0x0241FC70>, <socket._socketobject object at 0x0241FCA8>]
resaults: [<socket._socketobject object at 0x0241FCA8>]
#在无client连接和没有已连接的客户端发送消息,select所监听的inputs列表无增加,返回列表rList为空
inputs: [<socket._socketobject object at 0x0241FC70>, <socket._socketobject object at 0x0241FCA8>]
resaults: []
#client项server发送消息,select监听列表中客户端句柄conn_A8发生变化,select监听返回结果rList=[conn_A8]
inputs: [<socket._socketobject object at 0x024DFC70>, <socket._socketobject object at 0x024DFCA8>]
resaults: [<socket._socketobject object at 0x024DFCA8>] #接下来就有意思了,保持第一个客户端不断开,再打开第二个客户端client2,句柄ss_70发生变化(我们在服务端只创建了一个socket实例),又会产生一个新的client2的回话句柄conn_E0,追加至select监听列表inputs中
inputs: [<socket._socketobject object at 0x0241FC70>, <socket._socketobject object at 0x0241FCA8>]
resaults: [<socket._socketobject object at 0x0241FC70>]
inputs: [<socket._socketobject object at 0x0241FC70>, <socket._socketobject object at 0x0241FCA8>, <socket._socketobject object at 0x0241FCE0>]
resaults: []
#client2向server端发送消息,client2的回话句柄conn_E0发生变化,被返回,rList=[conn_E0]
inputs: [<socket._socketobject object at 0x0241FC70>, <socket._socketobject object at 0x0241FCA8>, <socket._socketobject object at 0x0241FCE0>]
resaults: [<socket._socketobject object at 0x0241FCE0>]

实例2

#!/usr/bin/env python
#-*- coding:utf-8 -*-
import socket
import select
import Queue
ss = socket.socket()
ss.bind(("localhost",8000))
ss.listen(5)
#设置为False,accept接受消息时为非阻塞
ss.setblocking(False)
#selec监听列表,若列表中哪个句柄发生变化,返回个readAble,否则readAble列表为空
rList = [ss]
#写列表,writeAble == wList,二者相等,select返回值即wList的值
wList = []
#定义一个字典,key:客户端句柄,value:接收和发送的消息队列;用于收和发之间共享数据
msg_queues = {}
while True:
readAble,writeAble,e = select.select(rList,wList,[],2)
for r in readAble:
if r == ss:
conn,addr = r.accept()
rList.append(conn)
else:
#创建接收的消息队列
msg_queues[r] = Queue.Queue()
try:
data = r.recv(1024)
#客户端断开连接会抛出:socket.error 10054异常,将此客户端连接句柄从select监听列表中移除
except socket.error,e:
rList.remove(r)
else:
#将接收到的消息加入句柄所对应的队列中
msg_queues[r].put(data)
#如果此client句柄wList列表不存在,就加入wList列表
if r not in wList:
wList.append(r)
for w in wList:
try:
w.sendall(msg_queues[w].get_nowait())
except Queue.Empty:
pass
#因为select监听wList时,只要wList列表中有,就返回wList中所有的句柄,所以使用完后需要删除
wList.remove(w)
del msg_queues[w]

select

socket之IO多路复用的更多相关文章

  1. socket的IO多路复用

    IO 多路复用 I/O多路复用指:通过一种机制,可以监视多个描述符,一旦某个描述符就绪(一般是读就绪或者写就绪),能够通知程序进行相应的读写操作. Linux Linux中的 select,poll, ...

  2. PHP实现网络Socket及IO多路复用

    一直以来,PHP很少用于socket编程,毕竟是一门脚本语言,效率会成为很大的瓶颈,但是不能说PHP就无法用于socket编程,也不能说PHP的socket编程性能就有多么的低,例如知名的一款PHP ...

  3. PHP实现系统编程(一) --- 网络Socket及IO多路复用【网摘】

    一直以来,PHP很少用于socket编程,毕竟是一门脚本语言,效率会成为很大的瓶颈,但是不能说PHP就无法用于socket编程,也不能说PHP的socket编程性能就有多么的低,例如知名的一款PHP ...

  4. python基础-11 socket,IO多路复用,select伪造多线程,select读写分离。socketserver源码分析

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

  5. 网络编程socket 结合IO多路复用select; epool机制分别实现单线程并发TCP服务器

    select版-TCP服务器 1. select 原理 在多路复用的模型中,比较常用的有select模型和epoll模型.这两个都是系统接口,由操作系统提供.当然,Python的select模块进行了 ...

  6. PHP7 网络编程(六)Socket和IO多路复用【待】

    https://blog.csdn.net/zhang197093/article/details/77366407

  7. python 全栈开发,Day44(IO模型介绍,阻塞IO,非阻塞IO,多路复用IO,异步IO,IO模型比较分析,selectors模块,垃圾回收机制)

    昨日内容回顾 协程实际上是一个线程,执行了多个任务,遇到IO就切换 切换,可以使用yield,greenlet 遇到IO gevent: 检测到IO,能够使用greenlet实现自动切换,规避了IO阻 ...

  8. (IO模型介绍,阻塞IO,非阻塞IO,多路复用IO,异步IO,IO模型比较分析,selectors模块,垃圾回收机制)

    参考博客: https://www.cnblogs.com/xiao987334176/p/9056511.html 内容回顾 协程实际上是一个线程,执行了多个任务,遇到IO就切换 切换,可以使用yi ...

  9. Python(七)Socket编程、IO多路复用、SocketServer

    本章内容: Socket IO多路复用(select) SocketServer 模块(ThreadingTCPServer源码剖析) Socket socket通常也称作"套接字" ...

随机推荐

  1. Python与数据库 sqlalchemy 建立声明层表对象的两种方式

    在对表对象进行建立的时候,通常有两种方式可以完成,以下是两种方式的建立过程对比 首先导入需要的模块,获取一个声明层 1 from sqlalchemy.sql.schema import Table, ...

  2. 前端笔记-dom

    dom(document object model) -文档对象模型,包含整个页面所有功能,可以通过调用方法的形式来操作页面,所以js和dom结合在一起可以写一些逻辑性的语言 dom的对象 dom有5 ...

  3. python_网络编程socket(TCP)

    服务端: import socket sk = socket.socket() #创建对象 sk.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) ...

  4. asp.net mvc(模式)和三层架构(BLL、DAL、Model)的联系与区别 转载自:http://blog.csdn.net/luoyeyu1989/article/details/8275866

    首先,MVC和三层架构,是不一样的. 三层架构中,DAL(数据访问层).BLL(业务逻辑层).WEB层各司其职,意在职责分离. MVC是 Model-View-Controller,严格说这三个加起来 ...

  5. 基于 C++ 的脚本语言 cpps 脚本

    cpps 脚本是一个基于 C++ 的脚本语言. 基础语法: if&else 接口说明 根据括号中数据判断执行相关代码. 代码演示 var i = toint(io.getc()); if(i  ...

  6. adb常用命令及简介

    平时开发android应用 的时候,我们都会用到包含在Android SDK中一系列的工具,或许我们通过Eclipse去调用,又或许,我们自己通过打开终端进行手动输入并且执行,下面我们来一起学习下这些 ...

  7. [Google Guava] 2.4-集合扩展工具类

    原文链接 译文链接 译者:沈义扬,校对:丁一 简介 有时候你需要实现自己的集合扩展.也许你想要在元素被添加到列表时增加特定的行为,或者你想实现一个Iterable,其底层实际上是遍历数据库查询的结果集 ...

  8. Oracle 物理结构(七) 文件-归档日志文件

    Oracle 物理结构(七) 文件-归档日志文件

  9. Noip2013 提高组 Day2 T1 积木大赛

    题目描述 春春幼儿园举办了一年一度的“积木大赛”.今年比赛的内容是搭建一座宽度为n的大厦,大厦可以看成由n块宽度为1的积木组成,第i块积木的最终高度需要是hi. 在搭建开始之前,没有任何积木(可以看成 ...

  10. http接口测试工具 REST Client

    以下几个工具为常用rest测试工具 1.Postman, 可以下载客户端或者安装浏览器插件 2.Insomnia,window客户端 3.Apizza,在线极客专属的api协作管理工具 ...