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,如需转载请自行联系原作者



相关文章
|
8天前
|
安全 Java 数据处理
Python网络编程基础(Socket编程)多线程/多进程服务器编程
【4月更文挑战第11天】在网络编程中,随着客户端数量的增加,服务器的处理能力成为了一个重要的考量因素。为了处理多个客户端的并发请求,我们通常需要采用多线程或多进程的方式。在本章中,我们将探讨多线程/多进程服务器编程的概念,并通过一个多线程服务器的示例来演示其实现。
|
8天前
|
存储 算法 Linux
【实战项目】网络编程:在Linux环境下基于opencv和socket的人脸识别系统--C++实现
【实战项目】网络编程:在Linux环境下基于opencv和socket的人脸识别系统--C++实现
24 6
|
1天前
|
机器学习/深度学习 Python
Python用LSTM长短期记忆神经网络对不稳定降雨量时间序列进行预测分析
Python用LSTM长短期记忆神经网络对不稳定降雨量时间序列进行预测分析
11 0
|
1天前
|
JSON 网络协议 API
Python网络编程面试题精讲
【4月更文挑战第15天】本文介绍了Python网络编程的面试重点,包括基础Socket编程、HTTP协议与requests库、异步编程与asyncio库。通过实例解析常见面试题,强调了非阻塞套接字、异常处理、HTTP状态码检查以及异步任务管理等关键点。提供代码示例帮助读者巩固概念,助力面试准备。
9 0
|
2天前
|
机器学习/深度学习 数据采集 数据可视化
R语言用加性多元线性回归、随机森林、弹性网络模型预测鲍鱼年龄和可视化
R语言用加性多元线性回归、随机森林、弹性网络模型预测鲍鱼年龄和可视化
91 7
|
2天前
|
机器学习/深度学习 API 算法框架/工具
R语言深度学习:用keras神经网络回归模型预测时间序列数据
R语言深度学习:用keras神经网络回归模型预测时间序列数据
13 0
|
2天前
|
机器学习/深度学习
HAR-RV-J与递归神经网络(RNN)混合模型预测和交易大型股票指数的高频波动率
HAR-RV-J与递归神经网络(RNN)混合模型预测和交易大型股票指数的高频波动率
13 0
|
2天前
|
机器学习/深度学习 存储 测试技术
使用PYTHON中KERAS的LSTM递归神经网络进行时间序列预测
使用PYTHON中KERAS的LSTM递归神经网络进行时间序列预测
|
3天前
|
编解码 网络协议 网络安全
2.H3CNE-网络参考模型
2.H3CNE-网络参考模型
|
3天前
|
机器学习/深度学习 资源调度 数据可视化
使用Python和Keras进行主成分分析、神经网络构建图像重建
使用Python和Keras进行主成分分析、神经网络构建图像重建