缘由 
之前写socket的CS模型代码,都是利用最原始的多线程方式。服务端是主线程,接到客户端的连接请求就从线程池中获取一个线程去处理整个socket连接的所有操作,虽然在连接数较短的情况下没有什么影响,但是当连接数很大的情况下,线程的切换和线程池的大小问题就明显起来了。

问题 
应该存在一种方式可以让一个线程去处理多个连接,在连接有事情做的时候才过去处理,不然的话线程就挂起,让线程的利用率更高,于是后来学习了select以及epoll。在这里我重点总结一下select

select的原理 
select是监听触发机制,监听可读和可写队列。当有事件发生时,进行遍历轮询事件发生的对象然后返回 
比如在服务端启动之后把服务端添加到select的可读监听队列中,当有客户端请求连接服务端时,select函数会返回一个可读事件再让服务端接受客户端的连接。 
select的返回方式可以是阻塞或者是非阻塞,非阻塞式的select处理方式是轮询的,会不断询问占用Cpu太多的资源和时间,所以建议使用阻塞等待返回的方式去使用select

优点: 
没有了多线程的创建、销毁、切换带来的效率和内存上的消耗 
缺点 
select存在一个最大可监听文件描述符数量,所以会收到最大连接监听的限制 
select在事件发生以后也是需要遍历监听对象,并不能直接定位到哪个对象,这个操作在对象数量庞大的情况下是个效率的瓶颈。所以后来有了epoll

程序流程描述: 
1. 在创建了server的socket以后,通过无限循环监听select事件执行相应的操作 
2. 客户端请求连接服务端,inputs非空,outputs为空,为queue增添客户端对象 ,readable非空,writeable为空 
3. 服务端接收客户端发送的数据,为outputs增添消息数据,readable不为空,writeable为空,如果接收失败说明客户端断开了连接,则终止监听此客户端的消息,回到第1步等待客户端连接 
4. outputs非空触发select事件,readable为空,writeable不为空,将queue中的数据发送到客户端,如果queue为空触发清除outputs操作 
5. 等待客户端发送数据,回到第2步

服务端代码:

  1. #!/usr/bin/env python
  2. #*-* coding:utf-8 *-*
  3. import select
  4. import socket
  5. import Queue
  6. import time
  7. import os
  8. class Server():
  9. #创建socket 套接字
  10. def __init__(self):
  11. self.server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
  12. self.server.setblocking(False)
  13. #配置参数
  14. self.server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
  15. self.server_address= ('127.0.0.1',8008)
  16. self.server.bind(self.server_address)
  17. self.server.listen(10)
  18. self.inputs = [self.server]
  19. self.outputs = []
  20. self.message_queues = {}
  21. #timeout = 20
  22. def run(self):
  23. while self.inputs:
  24. print "=================================="
  25. print "waiting for next event"
  26. print "inputs",self.inputs
  27. print "outputs",self.outputs
  28. print "queue", self.message_queues
  29. #readable , writable , exceptional = select.select(inputs, outputs, inputs, timeout) 最后一个是超时,当前连接要是超过这个时间的话,就会kill
  30. readable , writable , exceptional = select.select(self.inputs, self.outputs, self.inputs)
  31. print "readable , writable , exceptional",readable , writable , exceptional
  32. # When timeout reached , select return three empty lists
  33. if not (readable or writable or exceptional) :
  34. print "Time out ! "
  35. break;
  36. for s in readable :
  37. if s is self.server:
  38. #通过self.inputs查看是否有客户端来
  39. connection, client_address = s.accept()
  40. print " connection from ", client_address
  41. connection.setblocking(0)
  42. self.inputs.append(connection)
  43. self.message_queues[connection] = Queue.Queue()
  44. else:
  45. try:
  46. data = s.recv(1024)
  47. except:
  48. print " closing", client_address
  49. if s in self.outputs :
  50. self.outputs.remove(s)
  51. self.inputs.remove(s)
  52. s.close()
  53. #清除队列信息
  54. del self.message_queues[s]
  55. else:
  56. if data :
  57. print " received " , data , "from ",s.getpeername()
  58. self.message_queues[s].put(data)
  59. # Add output channel for response
  60. if s not in self.outputs:
  61. self.outputs.append(s)
  62. for s in writable:
  63. try:
  64. next_msg = self.message_queues[s].get_nowait()
  65. except Queue.Empty:
  66. print " " , s.getpeername() , 'queue empty'
  67. self.outputs.remove(s)
  68. else:
  69. print " sending " , next_msg , " to ", s.getpeername()
  70. os.popen('sleep 5').read()
  71. s.send(next_msg)
  72. for s in exceptional:
  73. print " exception condition on ", s.getpeername()
  74. #stop listening for input on the connection
  75. self.inputs.remove(s)
  76. if s in self.outputs:
  77. self.outputs.remove(s)
  78. s.close()
  79. #清除队列信息
  80. del self.message_queues[s]
  81. if __name__ == "__main__":
  82. s = Server()
  83. s.run()

客户端代码:

  1. # -*- coding:UTF-8 -*-
  2. import socket
  3. import os
  4. import signal
  5. import time, threading
  6. def SendDataToServer(sock):
  7. while True:
  8. put = str(raw_input())
  9. sock.send(put)
  10. def ReceiveData(sock):
  11. while True:
  12. try:
  13. data = sock.recv(1024)
  14. time.sleep(1)
  15. except:
  16. print "Server Down!"
  17. os._exit(0)
  18. else:
  19. if data:
  20. print "RECEIVE:",data
  21. if __name__ == "__main__":
  22. s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  23. s.connect(('127.0.0.1', 8008))
  24. send_tick = threading.Thread(target=SendDataToServer, args=(s,))
  25. rec_tick = threading.Thread(target=ReceiveData, args=(s,))
  26. send_tick.start()
  27. rec_tick.start()

Python Select模型(程序流程)(转)的更多相关文章

  1. Python Select模型

    IO多路复用 IO多路复用就是我们经常说的select epoll.select和epoll的好处是单个process就可以同时处理多个网络IO.基本原理是select\epoll会不断的轮询所负责的 ...

  2. 基于select的python聊天室程序

    python网络编程具体参考<python select网络编程详细介绍>. 在python中,select函数是一个对底层操作系统的直接访问的接口.它用来监控sockets.files和 ...

  3. 基于Select模型通信程序的编写,编译和执行

    任务目标 编写Win32程序模拟实现基于Select模型的两台计算机之间的通信,要求编程实现服务器端与客户端之间双向数据传递.客户端向服务器端发送"计算从1到100的奇数和",服务 ...

  4. 基于Select模型的Windows TCP服务端和客户端程序示例

    最近跟着刘远东老师的<C++百万并发网络通信引擎架构与实现(服务端.客户端.跨平台)>,Bilibili视频地址为C++百万并发网络通信引擎架构与实现(服务端.客户端.跨平台),重新复习下 ...

  5. 关于 Poco::TCPServer框架 (windows 下使用的是 select模型) 学习笔记.

    说明 为何要写这篇文章 ,之前看过阿二的梦想船的<Poco::TCPServer框架解析> http://www.cppblog.com/richbirdandy/archive/2010 ...

  6. 【转】Select模型原理

    Select模型原理利用select函数,判断套接字上是否存在数据,或者能否向一个套接字写入数据.目的是防止应用程序在套接字处于锁定模式时,调用recv(或send)从没有数据的套接字上接收数据,被迫 ...

  7. Select模型原理

    Select模型原理 利用select函数,推断套接字上是否存在数据,或者是否能向一个套接字写入数据.目的是防止应用程序在套接字处于锁定模式时,调用recv(或send)从没有数据的套接字上接收数据, ...

  8. Windows I/O模型之一:Select模型

    1.概念理解 在进行网络编程时,我们常常见到同步(Sync)/异步(Async),阻塞(Block)/非阻塞(Unblock) 四种调用模式: 同步:所谓同步,就是在发出一个功能调用时,在没有得到结果 ...

  9. python select模块详解

    要理解select.select模块其实主要就是要理解它的参数, 以及其三个返回值.select()方法接收并监控3个通信列表, 第一个是所有的输入的data,就是指外部发过来的数据,第2个是监控和接 ...

随机推荐

  1. 在不安装oracle客户端的情况下,使用PLSQL

    一般在使用plsql时,会结合oracle客户端来使用,这样方便把数据库连接信息添加到plsql中.不过oracle客户端软件有点庞大,安装起来不太方便,所以在网上找到一种不依赖oracle客户端来使 ...

  2. Nginx安装与使用 及在redhat 中的简单安装方式

    首先说下在redhat中的安装方法, 正常安装nginx 需要安装很多的依赖,最后再安装nginx,而且很容易出错. 在nginx官方上有这么一段描述: Pre-Built Packages for ...

  3. DP 传球问题

    洛谷P1057 传球问题 分析:经过m次传球到第i个人的方法可以由经过m-1次传球到第i个人和到第i-1个人传递得来 设dp[i][j]为经过j次传球后到达第i个人的方法数,可得到状态转移方程为: d ...

  4. Mybatis中int insertSelective()的相关问题

    1.selective的意思是:选择性2.insertSelective--选择性保存数据:比如User里面有三个字段:id,name,age,password但是我只设置了一个字段:User u=n ...

  5. 【IDEA】【6】Maven打包

    1,打包成jar包 右侧工具栏Maven Projects->项目名称->Lifecycle->package 2,打包时去掉test 右侧工具栏Maven Projects,打开后 ...

  6. 【基础知识】【1】CDN

    正文: CDN:Content Delivery Network,内容分发网络.使用户访问离ta最近的资源服务器,优化访问速度 优点: 1,内容可以共享,不同站点的同一文件可以不用多次缓存 2,增加下 ...

  7. const typedef 和指针的问题(这里必须初始化的才初始化了,不必须的则没有初始化)

    这里很容易搞混: tyepdef double dou;//这里是dou是double的别名 #include<iostream> using namespace std; int mai ...

  8. Oracle 聚合函数

    聚合函数: SQL中提供的聚合函数可以用来统计.求和.求最值等等. 此处采用Oracle 11g中其他用户SCOTT中的EMP表,进行演示. –COUNT:统计行数量 COUNT(*)统计的是结果集的 ...

  9. chrome 浏览器去掉输入框背景透明色

    chrome浏览器选择记住密码的账号,输入框会自动加上黄色的背景,有些设计输入框是透明背景的,需要去除掉这个黄色的背景: 这个黄色背景是谷歌浏览器默认的样式 user agent stylesheet ...

  10. array 数组去重 过滤空值等方法

    去重操作 第一种方式, ES 6 引入的新书据结构 Set 本身就是没有重复数据的, 可以使用这个数据结构来转化数组.时间复杂度 O(n) 123456 const target = [];const ...