Python中使用select模块实现非阻塞的IO


Posted in Python onFebruary 03, 2015

Socket的英文原义是“孔”或“插座”。作为BSD UNIX的进程通信机制,取后一种意思。通常也称作”套接字”,用于描述IP地址和端口,是一个通信链的句柄。在Internet上的主机一般运行了多个服务软件,同时提供几种服务。每种服务都打开一个Socket,并绑定到一个端口上,不同的端口对应于不同的服务。Socket正如其英文原意那样,像一个多孔插座。一台主机犹如布满各种插座的房间,每个插座有一个编号,有的插座提供220伏交流电, 有的提供110伏交流电,有的则提供有线电视节目。 客户软件将插头插到不同编号的插座,就可以得到不同的服务。?百度百科

socket如此重要,现在的网络编程几乎都是用的它,它起源于Unix,而Unix/Linux基本哲学之一就是“一切皆文件”,都可以用打开,读写,关闭的模式来操作。然而,对于网络服务来说,往往针对大量的客户群体,例如web,对于这类服务,必须要保证既能并行处理请求,又能保证服务的稳定。但传统的socket在处理并发方面有所欠缺,借助与select模块,能够较好的是要非阻塞的IO。

Python中的select模块以列表形式接受四个参数,分别是需要监控的可读文件对象,可写文件对象,产生异常的文件对象和超时设置,当监控的对象发生变化时,select会返回发生变化的对象列表。下面是用select实现一个简单的聊天室:

#!/usr/bin/env python
#*-* coding:utf-8 *-*
import socket
import select
import sys
import signal
class ChatServer():
  def __init__(self,host,port,timeout=10,backlog=5):
    #记录连接的客户端数量
    self.clients =0
    #存储连接的客户端socket和地址对应的字典
    self.clientmap={}
    #存储连接的客户端socket
    self.outputs = []
    #建立socket
    self.server=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    self.server.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
    self.server.bind((host,port))
    self.server.listen(backlog)
    #增加信号处理
    signal.signal(signal.SIGINT,self.sighandler) 
  def sighandler(self):
    sys.stdout.write("Shutdown Server......\n")
    #向已经连接客户端发送关系信息,并主动关闭socket
    for output in self.outputs:
      output.send("Shutdown Server")
      output.close()
    #关闭listen
    self.server.close()
    sys.stdout.flush()
  #主函数,用来启动服务器
  def run(self):
    #需要监听的可读对象
    inputs=[self.server]
    
    runing=True
    #添加监听主循环
    while runing:
      try:
        readable,writeable,exceptional = select.select(inputs,self.outputs,[])
        #此处会被select模块阻塞,只有当监听的三个参数发生变化时,select才会返回
      except select.error,e:
        break
      #当返回的readable中含有本地socket的信息时,表示有客户端正在请求连接
      if self.server in readable:
        #接受客户端连接请求
        client,addr=self.server.accept()
        sys.stdout.write("New Connection from %s\n"%str(addr))
        sys.stdout.flush()
        #更新服务器上客户端连接情况
        #1,数量加1
        #2,self.outputs增加一列
        #3,self.clientmap增加一对
        #4, 给input添加可读监控
        self.clients += 1
        self.outputs.append(client)
        self.clientmap[client]=addr
        inputs.append(client)
      
      #readable中含有已经添加的客户端socket,并且可读
      #说明 1,客户端有数据发送过来或者 2,客户端请求关闭
      elif len(readable) != 0:
        #1, 取出这个列表中的socket
        csock=readable[0]
        #2, 根据这个socket,在事先存放的clientmap中,去除客户端的地址,端口的详细信息
        host,port = self.clientmap[csock]
        #3,取数据, 或接受关闭请求,并处理
        #注意,这个操作是阻塞的,但是由于数据是在本地缓存之后,所以速度会非常快
        try:
          data = csock.recv(1024).strip()
          for cs in self.outputs:
            if cs != csock:
              cs.send("%s\n"%data)
        except socket.error,e:
          self.clients -= 1
          inputs.remove(csock)
          self.outputs.remove(csock)
          del self.clientmap[csock]
      #print self.outputs
    self.server.close()
        
if __name__ == "__main__":
  chat=ChatServer("",8008)
  chat.run()

运行这个脚本,然后用任意客户端如telnet或netcat连接8008端口,多个客户端之间就可以进行对话。

其实select模块本身是阻塞的,当需要监控的socket发生变化时,select作出返回,下面的程序会继续执行,程序根据select的返回值,对各种情况作出处理。

Python 相关文章推荐
用python实现面向对像的ASP程序实例
Nov 10 Python
python使用PIL缩放网络图片并保存的方法
Apr 24 Python
python 创建弹出式菜单的实现代码
Jul 11 Python
python3第三方爬虫库BeautifulSoup4安装教程
Jun 19 Python
Django Sitemap 站点地图的实现方法
Apr 29 Python
python的re模块使用方法详解
Jul 26 Python
在python3中实现更新界面
Feb 21 Python
Python中remove漏删和索引越界问题的解决
Mar 18 Python
Python3 mmap内存映射文件示例解析
Mar 23 Python
Python实现的北京积分落户数据分析示例
Mar 27 Python
自定义实现 PyQt5 下拉复选框 ComboCheckBox的完整代码
Mar 30 Python
全面介绍python中很常用的单元测试框架unitest
Dec 14 Python
Python异常学习笔记
Feb 03 #Python
Python中的迭代器漫谈
Feb 03 #Python
Python描述器descriptor详解
Feb 03 #Python
理解Python中的With语句
Feb 02 #Python
Linux环境下MySQL-python安装过程分享
Feb 02 #Python
Python中用pycurl监控http响应时间脚本分享
Feb 02 #Python
Python列表(list)常用操作方法小结
Feb 02 #Python
You might like
php中使用cookie来保存用户登录信息的实现代码
2012/03/08 PHP
php 注释规范
2012/03/29 PHP
CI框架在CLI下执行占用内存过大问题的解决方法
2014/06/17 PHP
使用Codeigniter重写insert的方法(推荐)
2017/03/23 PHP
Laravel 对某一列进行筛选然后求和sum()的例子
2019/10/10 PHP
HTML 自动伸缩的表格Table js实现
2009/04/01 Javascript
vs2003 js文件编码问题的解决方法
2010/03/20 Javascript
js中各浏览器中鼠标按键值的差异
2011/04/07 Javascript
JS模拟面向对象全解(一、类型及传递)
2011/07/13 Javascript
自写的jQuery异步加载数据添加事件
2014/05/15 Javascript
原生js实现放大镜效果
2017/01/11 Javascript
JS实现二叉查找树的建立以及一些遍历方法实现
2017/04/17 Javascript
seajs中最常用的7个功能、配置示例
2017/10/10 Javascript
详解AngularJS之$window窗口对象
2018/01/17 Javascript
VUE2.0中Jsonp的使用方法
2018/05/22 Javascript
一份超级详细的Vue-cli3.0使用教程【推荐】
2018/11/15 Javascript
微信小程序新手教程之页面打开数量限制
2019/03/03 Javascript
JavaScript实现身份证验证代码实例
2019/08/26 Javascript
微信小程序订阅消息(java后端实现)开发
2020/06/01 Javascript
手把手教你实现 Promise的使用方法
2020/09/02 Javascript
Python基于回溯法解决01背包问题实例
2017/12/06 Python
Python3 queue队列模块详细介绍
2018/01/05 Python
Django页面数据的缓存与使用的具体方法
2019/04/23 Python
基于django ManyToMany 使用的注意事项详解
2019/08/09 Python
利用python list完成最简单的DB连接池方法
2019/08/09 Python
关于numpy.where()函数 返回值的解释
2019/12/06 Python
Python cookie的保存与读取、SSL讲解
2020/02/17 Python
python多进程下的生产者和消费者模型
2020/05/07 Python
如何利用python 读取配置文件
2021/01/06 Python
印度购物网站:TATA CLiQ
2017/11/23 全球购物
留学生如何写好自荐信
2013/12/27 职场文书
《二泉映月》教学反思
2014/04/15 职场文书
警察先进个人事迹材料
2014/05/16 职场文书
民族学专业大学生职业规划范文:清晰未来的构想
2014/09/20 职场文书
中考百日冲刺决心书
2015/09/22 职场文书
80后创业总结的9条职场用人思想,记得收藏
2019/08/13 职场文书