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



相关文章
|
4天前
|
机器学习/深度学习 PyTorch 算法框架/工具
【从零开始学习深度学习】28.卷积神经网络之NiN模型介绍及其Pytorch实现【含完整代码】
【从零开始学习深度学习】28.卷积神经网络之NiN模型介绍及其Pytorch实现【含完整代码】
|
4天前
|
机器学习/深度学习 PyTorch 算法框架/工具
【从零开始学习深度学习】26.卷积神经网络之AlexNet模型介绍及其Pytorch实现【含完整代码】
【从零开始学习深度学习】26.卷积神经网络之AlexNet模型介绍及其Pytorch实现【含完整代码】
|
10天前
|
网络协议 算法 Linux
【嵌入式软件工程师面经】Linux网络编程Socket
【嵌入式软件工程师面经】Linux网络编程Socket
27 1
YOLOv8打印模型结构配置信息并查看网络模型详细参数:参数量、计算量(GFLOPS)
YOLOv8打印模型结构配置信息并查看网络模型详细参数:参数量、计算量(GFLOPS)
|
4天前
|
机器学习/深度学习 数据采集 自然语言处理
【注意力机制重大误区】网络模型增加注意力机制后,性能就一定会得到提升?有哪些影响因素?
【注意力机制重大误区】网络模型增加注意力机制后,性能就一定会得到提升?有哪些影响因素?
|
4天前
|
域名解析 缓存 网络协议
|
4天前
|
Unix Python
Python基础教程(第3版)中文版 第14章 网络编程(笔记)
Python基础教程(第3版)中文版 第14章 网络编程(笔记)
|
4天前
|
机器学习/深度学习 PyTorch 算法框架/工具
【从零开始学习深度学习】29.卷积神经网络之GoogLeNet模型介绍及用Pytorch实现GoogLeNet模型【含完整代码】
【从零开始学习深度学习】29.卷积神经网络之GoogLeNet模型介绍及用Pytorch实现GoogLeNet模型【含完整代码】
|
4天前
|
机器学习/深度学习 PyTorch 算法框架/工具
【从零开始学习深度学习】27.卷积神经网络之VGG11模型介绍及其Pytorch实现【含完整代码】
【从零开始学习深度学习】27.卷积神经网络之VGG11模型介绍及其Pytorch实现【含完整代码】
|
4天前
|
机器学习/深度学习 算法 PyTorch
【从零开始学习深度学习】25.卷积神经网络之LeNet模型介绍及其Pytorch实现【含完整代码】
【从零开始学习深度学习】25.卷积神经网络之LeNet模型介绍及其Pytorch实现【含完整代码】

热门文章

最新文章