python实现select和epoll模型socket网络编程

简介:

这里简单搞搞select和eopll的接口开发 ~


select目前几乎在所有的平台上支持,其良好跨平台支持也是它的一个优点,事实

上从现在看来,这也是它所剩不多的优点之一,现在其实更多的人用epoll,在

python下epoll文档有点少,就先讲究搞搞select ~


select的一个缺点在于单个进程能够监视的文件描述符的数量存在最大限制,在

Linux上一般为1024,不过可以通过修改宏定义甚至重新编译内核的方式提升这一

限制。


说点我的理解,要是用烦了多线程的网络编程,可以试试select的模型。


传递给 select 的参数是几个列表,分别表示读事件、写事件和错误事件。select 方法返回三个列表,其中包含满足条件的对象(读、写和异常)。


服务端的代码:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#coding:utf-8
import  socket,select
import  time
import  os
#xiaorui.cc
host  =  "localhost"
port  =  50000
=  socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.bind((host,port))
s.listen( 5 )
while  1 :
      infds,outfds,errfds  =  select.select([s,],[],[], 5 )
      if  len (infds) ! =  0 :
         clientsock,clientaddr  =  s.accept()
         buf  =  clientsock.recv( 8196 )
         if  len (buf) ! =  0 :
             print  (buf)
             os.popen( 'sleep 10' ).read()                                                                                                      
         clientsock.close()
#     print "no data coming"


客户端的代码:


1
2
3
4
5
6
7
8
9
10
#coding:utf-8
import  socket,select
#xiaorui.cc
host  =  "localhost"
port  =  50000
=  socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect((host,port))
                                                                                                                                                                                                                                                                                                                                                                                                                                                     
s.send( "coming from select client" )
s.close()



170058459.jpg


一个完成的select的例子:

这里有队列的概念

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


关于epoll的方面,大家可以看看这个老外的文档,写不错 ~


select是轮询、epoll是触发式的,所以epoll的效率高。


参考的文档地址:http://scotdoyle.com/python-epoll-howto.html


下面是用epoll实现一个服务端 ~


blog from xiaorui.cc


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
import  socket, select
EOL1 = b '\n\n'
EOL2 = b '\n\r\n'
response  = b 'HTTP/1.0 200 OK\r\nDate: Mon, 1 Jan 1996 01:01:01 GMT\r\n'
response += b 'Content-Type: text/plain\r\nContent-Length: 13\r\n\r\n'
response += b 'Hello, world!'
serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
serversocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR,  1 )
serversocket.bind(( '0.0.0.0' 8080 ))
serversocket.listen( 1 )
serversocket.setblocking( 0 )
epoll = select.epoll()
epoll.register(serversocket.fileno(), select.EPOLLIN)
try :
    connections = {}; requests = {}; responses = {}
    while  True:
       events = epoll.poll( 1 )
       for  fileno, event  in  events:
          if  fileno == serversocket.fileno():
             connection, address = serversocket.accept()
             connection.setblocking( 0 )
             epoll.register(connection.fileno(), select.EPOLLIN)
             connections[connection.fileno()] = connection
             requests[connection.fileno()] = b ''
             responses[connection.fileno()] = response
          elif event & select.EPOLLIN:
             requests[fileno] += connections[fileno].recv( 1024 )
             if  EOL1  in  requests[fileno] or EOL2  in  requests[fileno]:
                epoll.modify(fileno, select.EPOLLOUT)
                connections[fileno].setsockopt(socket.IPPROTO_TCP, socket.TCP_CORK,  1 )
                print( '-' * 40  '\n'  + requests[fileno].decode()[:- 2 ])
          elif event & select.EPOLLOUT:
             byteswritten = connections[fileno].send(responses[fileno])
             responses[fileno] = responses[fileno][byteswritten:]
             if  len(responses[fileno]) ==  0 :
                connections[fileno].setsockopt(socket.IPPROTO_TCP, socket.TCP_CORK,  0 )
                epoll.modify(fileno,  0 )
                connections[fileno].shutdown(socket.SHUT_RDWR)
          elif event & select.EPOLLHUP:
             epoll.unregister(fileno)
             connections[fileno].close()
             del connections[fileno]
finally :
    epoll.unregister(serversocket.fileno())



Epoll的最大好处是不会随着FD的数目增长而降低效率,在select中采用轮询处理,每个fd的处理情况,而epoll是维护一个队列,直接看队列是不是空就可以了。


在这里也推荐大家用epoll写服务端的东西,当然我自己理解的不够好,咱们多交流 !!!




 本文转自 rfyiamcool 51CTO博客,原文链接:http://blog.51cto.com/rfyiamcool/1344824,如需转载请自行联系原作者



相关文章
|
1天前
|
存储 网络协议 关系型数据库
Python从入门到精通:2.3.2数据库操作与网络编程——学习socket编程,实现简单的TCP/UDP通信
Python从入门到精通:2.3.2数据库操作与网络编程——学习socket编程,实现简单的TCP/UDP通信
|
1天前
|
机器学习/深度学习 算法 搜索推荐
Python用机器学习算法进行因果推断与增量、增益模型Uplift Modeling智能营销模型
Python用机器学习算法进行因果推断与增量、增益模型Uplift Modeling智能营销模型
28 12
|
1天前
|
机器学习/深度学习 算法 vr&ar
PYTHON用时变马尔可夫区制转换(MARKOV REGIME SWITCHING)自回归模型分析经济时间序列
PYTHON用时变马尔可夫区制转换(MARKOV REGIME SWITCHING)自回归模型分析经济时间序列
13 4
|
5天前
|
数据可视化 Python
Python模型评估与选择:面试必备知识点
【4月更文挑战第17天】本文深入探讨了Python模型评估与选择在面试中的关键点,包括性能度量、过拟合与欠拟合识别、模型比较与选择、模型融合和偏差-方差权衡。强调了避免混淆评估指标、忽视模型验证和盲目追求高复杂度模型的常见错误,并提供相关代码示例,如交叉验证、网格搜索和超参数调优。通过理解这些概念和技巧,可在面试中展示出色的数据科学能力。
31 12
|
7天前
|
JSON 网络协议 API
Python网络编程面试题精讲
【4月更文挑战第15天】本文介绍了Python网络编程的面试重点,包括基础Socket编程、HTTP协议与requests库、异步编程与asyncio库。通过实例解析常见面试题,强调了非阻塞套接字、异常处理、HTTP状态码检查以及异步任务管理等关键点。提供代码示例帮助读者巩固概念,助力面试准备。
13 0
|
7天前
|
机器学习/深度学习 数据可视化 Linux
python用ARIMA模型预测CO2浓度时间序列实现
python用ARIMA模型预测CO2浓度时间序列实现
20 0
|
7天前
|
Python 数据可视化 索引
PYTHON用GARCH、离散随机波动率模型DSV模拟估计股票收益时间序列与蒙特卡洛可视化
PYTHON用GARCH、离散随机波动率模型DSV模拟估计股票收益时间序列与蒙特卡洛可视化
20 0
PYTHON用GARCH、离散随机波动率模型DSV模拟估计股票收益时间序列与蒙特卡洛可视化
|
7天前
|
机器学习/深度学习 Python 数据处理
Python中利用长短期记忆模型LSTM进行时间序列预测分析 - 预测电力负荷数据
Python中利用长短期记忆模型LSTM进行时间序列预测分析 - 预测电力负荷数据
32 0
Python中利用长短期记忆模型LSTM进行时间序列预测分析 - 预测电力负荷数据
|
7天前
|
数据挖掘 vr&ar Python
Python金融时间序列模型ARIMA 和GARCH 在股票市场预测应用
Python金融时间序列模型ARIMA 和GARCH 在股票市场预测应用
34 10
|
7天前
|
机器学习/深度学习 存储 算法
PYTHON集成机器学习:用ADABOOST、决策树、逻辑回归集成模型分类和回归和网格搜索超参数优化
PYTHON集成机器学习:用ADABOOST、决策树、逻辑回归集成模型分类和回归和网格搜索超参数优化
30 7