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



相关文章
|
6月前
|
C++
基于Reactor模型的高性能网络库之地址篇
这段代码定义了一个 InetAddress 类,是 C++ 网络编程中用于封装 IPv4 地址和端口的常见做法。该类的主要作用是方便地表示和操作一个网络地址(IP + 端口)
336 58
|
5月前
|
机器学习/深度学习 数据采集 数据挖掘
基于 GARCH -LSTM 模型的混合方法进行时间序列预测研究(Python代码实现)
基于 GARCH -LSTM 模型的混合方法进行时间序列预测研究(Python代码实现)
203 2
|
6月前
|
网络协议 算法 Java
基于Reactor模型的高性能网络库之Tcpserver组件-上层调度器
TcpServer 是一个用于管理 TCP 连接的类,包含成员变量如事件循环(EventLoop)、连接池(ConnectionMap)和回调函数等。其主要功能包括监听新连接、设置线程池、启动服务器及处理连接事件。通过 Acceptor 接收新连接,并使用轮询算法将连接分配给子事件循环(subloop)进行读写操作。调用链从 start() 开始,经由线程池启动和 Acceptor 监听,最终由 TcpConnection 管理具体连接的事件处理。
242 2
|
6月前
基于Reactor模型的高性能网络库之Tcpconnection组件
TcpConnection 由 subLoop 管理 connfd,负责处理具体连接。它封装了连接套接字,通过 Channel 监听可读、可写、关闭、错误等
195 1
|
6月前
|
JSON 监控 网络协议
干货分享“对接的 API 总是不稳定,网络分层模型” 看电商 API 故障的本质
本文从 OSI 七层网络模型出发,深入剖析电商 API 不稳定的根本原因,涵盖物理层到应用层的典型故障与解决方案,结合阿里、京东等大厂架构,详解如何构建高稳定性的电商 API 通信体系。
|
3月前
|
机器学习/深度学习 数据采集 人工智能
深度学习实战指南:从神经网络基础到模型优化的完整攻略
🌟 蒋星熠Jaxonic,AI探索者。深耕深度学习,从神经网络到Transformer,用代码践行智能革命。分享实战经验,助你构建CV、NLP模型,共赴二进制星辰大海。
|
4月前
|
机器学习/深度学习 传感器 算法
【无人车路径跟踪】基于神经网络的数据驱动迭代学习控制(ILC)算法,用于具有未知模型和重复任务的非线性单输入单输出(SISO)离散时间系统的无人车的路径跟踪(Matlab代码实现)
【无人车路径跟踪】基于神经网络的数据驱动迭代学习控制(ILC)算法,用于具有未知模型和重复任务的非线性单输入单输出(SISO)离散时间系统的无人车的路径跟踪(Matlab代码实现)
323 2
|
4月前
|
机器学习/深度学习 并行计算 算法
【CPOBP-NSWOA】基于豪冠猪优化BP神经网络模型的多目标鲸鱼寻优算法研究(Matlab代码实现)
【CPOBP-NSWOA】基于豪冠猪优化BP神经网络模型的多目标鲸鱼寻优算法研究(Matlab代码实现)
119 8
|
4月前
|
机器学习/深度学习 数据采集 并行计算
多步预测系列 | LSTM、CNN、Transformer、TCN、串行、并行模型集合研究(Python代码实现)
多步预测系列 | LSTM、CNN、Transformer、TCN、串行、并行模型集合研究(Python代码实现)
468 2
|
6月前
基于Reactor模型的高性能网络库之Poller(EpollPoller)组件
封装底层 I/O 多路复用机制(如 epoll)的抽象类 Poller,提供统一接口支持多种实现。Poller 是一个抽象基类,定义了 Channel 管理、事件收集等核心功能,并与 EventLoop 绑定。其子类 EPollPoller 实现了基于 epoll 的具体操作,包括事件等待、Channel 更新和删除等。通过工厂方法可创建默认的 Poller 实例,实现多态调用。
355 60

推荐镜像

更多