Python epoll for network programming IO multiplexing

Source: Internet
Author: User
Tags epoll

Python network programming--io multiplexing EPOLL1, kernel Epoll model explained

This section refers to the http://blog.csdn.net/mango_song/article/details/42643971 blog and organizes

First, we define the concept of flow, a stream can be a file, socket,pipe, and so on can do I/O operations of kernel objects. Whether it's a file, a socket (socket), or a pipe, we can think of them as streams.

We then discuss I/O operations, which we can read from the stream through read, and we can write the data to the stream through write. Now suppose 1 scenarios, we need to read the data from the stream, but there is no data in the stream (the typical example is that the client is going to read the data from the socket, but the server has not yet transmitted the data back).

Blocking: What is the concept of blocking? For example, you are waiting for a courier at some time, but you do not know when the courier will come over, and you do not have anything else to do (or that the next thing to wait for the courier to do); then you can go to bed, because you know the delivery when the goods are sent to you must call (assuming you can wake you).

Non-blocking busy polling: Then the above, such as the example of the courier, if using a busy polling method, then you need to know the courier's mobile phone number, and then every minute to give him a call: "You arrived?" ”

It is clear that the average person will not use the second approach, not only to appear without brains, wasting money, not to say, but also occupy a large number of courier staff time.

Most programs also do not use the second approach, because the first method is economical and simple, the economy refers to the consumption of very little CPU time, if the thread sleeps, it will fall out of the system scheduling queue, temporarily do not partition the CPU precious time slices.

To understand how blocking is going, let's talk about buffers, as well as kernel buffers, and finally explain the I/O events. The introduction of buffers is a frequent system call to reduce frequent I/O operations (you know it is slow), and when you manipulate a stream, it is more of a buffer unit than the user space. Buffers are also required for the kernel.

Suppose there is a pipeline, process A is the writer of the pipeline, and B is the read-out side of the pipeline. Assuming that the kernel buffer is empty at first, B is blocked as a read-out party. Then first a to the pipeline write, when the kernel buffer from the empty state to non-empty state, the kernel will produce an event tells B to wake up, this event is called "Buffer non-empty". However, after the "buffer non-null" event notifies B, B has not yet read the data, and the kernel has promised not to discard the data in the write pipeline, a write data will be stuck in the kernel buffer, if the kernel buffer is full, B still does not start to read the data, the final kernel buffer will be filled, this time will produce a i/ o event, tell process A, you should wait (block), we define this event as "buffer full". Assuming b finally began to read the data, and then the kernel buffer is empty, the kernel will tell a, the kernel buffer is empty, you can wake up from the sleep, continue to write the data, we call this event "buffer is not full." Perhaps the event Y1 has notified a, but a has no data written, and B continues to read the data, knowing that the kernel buffer is empty. This time the kernel tells B that you need to block it! , we set the time to "buffer empty".

These four scenarios cover four I/O events, kernel buffers are full, kernel buffers are empty, kernel buffers are not empty, kernel buffers are not full. These four I/O events are the root of a blocking synchronization. (If you do not understand what "sync" is, learn about the operating system's lock, semaphore, condition variables, and other task synchronization aspects.)

Then let's talk about the drawbacks of blocking I/O. However, in blocking I/O mode, a thread can handle only one stream of I/O events. If you want to work with multiple streams at the same time, either multi-process (fork) or multithreaded (pthread_create), unfortunately neither of these methods is efficient. Then consider the I/O mode of non-blocking busy polling, and we find that we can handle multiple streams at the same time (switching a stream from blocking mode to non-blocking mode is not discussed again):

 while true {       for in  stream[]; {             if  i has data             read until unavailable       }  }

All we have to do is ask all the flow from beginning to end and start over again. This makes it possible to process multiple streams, but this is obviously not a good idea, because if all the streams have no data, the CPU will be wasted. To add that, in blocking mode, the kernel handles I/O events as blocking or waking, while non-blocking mode gives the I/O events to other objects (select and Epoll described later) and even ignores them directly.

In order to avoid the CPU idling, you can introduce an agent (at first there is a agent called Select, and later a proxy called poll, but the two are the same nature). This agent is very powerful, can observe many streams of I/O events at the same time, in idle time, will block the current thread, when there is one or more flows with I/O events, wake up from the blocking state, so our program will poll all the stream (so we can get the "busy" word removed). The code looks like this:

 while true {        select (streams[])        for in  streams[] {              if  I have Data              read until unavailable         }  

Thus, if there is no I/O event, our program will block at select. But there's still a problem, and we just know from select that there is an I/O event, but I don't know what the flow is (there may be one, multiple, or even all), we can only poll all the streams with no difference, find the stream that can read the data, or write the data, To operate on them.

But with SELECT, we have an O (n) non-differential polling complexity, and the more streams we process, the longer each non-differential polling time.    Once again said so much, finally can explain epoll well. Epoll can be understood as the event poll, Unlike busy polling and non-differential polling, Epoll will only notify us of what kind of I/O events occurred.。    At this point we make sense of the operation of these streams (the complexity is reduced to O (1)). Before discussing the implementation details of Epoll, the Epoll related actions are listed:
1 epoll_create Create a Epoll object, general EPOLLFD = epoll_create ()  2 epoll_ctl (Epoll_add/epoll_del), add to Epoll object Delete an  event of a stream 3   such  as 4 epoll_ctl (EPOLLFD, Epoll_ctl_add, Socket, epollin);// Register buffer non-empty event, there  is data inflow 5 Epoll_ CTL (EPOLLFD, Epoll_ctl_del, Socket, epollout);// register buffer not full event, that is, stream  can be written to 6 epoll_wait (EPOLLFD,...) Wait until the registered event occurs   7 (note: When the read-write to a non-blocking stream occurs when the buffer is full or the buffer is empty, Write/read returns-1 and sets Errno=eagain. Epoll only cares about buffer non-full and buffer non-empty events).  

The code of a epoll pattern probably looks like

2 Epoll in Python

From the above, Epoll is an improvement to the Select and poll models, which improves the performance of network programming and is widely used in the C/s architecture of large-scale concurrent requests.

1. Trigger mode:

Edge trigger/Level trigger, only for unix/linux operating system

2. Schematic diagram

3. General steps

    1. Create an Epoll object--creates 1 Epoll objects
    2. The Epoll object to monitor specific events on specific sockets--tells Epoll objects to listen for the specified event on the specified socket
    3. Ask the Epoll object which sockets may has had the specified event since the last query--ask the Epoll object which socket has been referred to since the previous query Set of events
    4. Perform some action on those sockets--perform some operations on these sockets
    5. The Epoll object to modify the list of sockets and/or events to monitor--tells Epoll objects, modifies the socket list and/or events, and monitors
    6. Repeat steps 3 through 5 until finished--repeat step 3-5 until completed
    7. Destroy the Epoll object--destroy Epoll objects

4. Related usage

Import= Select.epoll () creates a Epoll object Epoll.register (file handle, event type) to register the file handle to be monitored and the event event type: SELECT. Epollin readable    Event Select. Epollout writable   Event Select. Epollerr   Error Event Select. Epollhup   Client Disconnects event Epoll.unregister (file handle)   destroys a file handle Epoll.poll (timeout)  when the file handle changes, it is actively reported to the user process as a list, Timeout                     is a time-out that defaults to 1, that is, waiting until the file handle changes, if specified as 1                     then Epoll reports the current file handle changes every 1 seconds, and returns an empty Epoll.fileno if there is no change ( Returns the control file descriptor for the Epoll (return the Epoll Control descriptor) epoll.modfiy (fineno,event) Fineno for the file descriptor event type  The function is to modify the file descriptor corresponding to the event EPOLL.FROMFD (Fileno) to create 1 Epoll objects from 1 specified file descriptors epoll.close ()   Close the control file descriptor of the Epoll object

5 Example: The client sends the data to the client and returns the received data to the clients

defepoll_socket ():ImportSocketImportSelectImportQueue#creating a Socket objectServerSocket =Socket.socket (socket.af_inet, socket. SOCK_STREAM)#Set IP address multiplexingServersocket.setsockopt (socket. Sol_socket, SOCKET. SO_REUSEADDR, 1)    #IP Address and port numberServer_address = ("127.0.0.1", 6666)    #Bind IP AddressServersocket.bind (server_address)#Monitor and set the maximum number of connectionsServersocket.listen (10)    Print  "server started successfully, listening IP:", Server_address#server-side set non-blockingserversocket.setblocking (False)#Timeout periodTimeout = 10#Create a Epoll event object, and subsequent events to be monitored are added to itEpoll =Select.epoll ()#Register server listens for FD to wait read event collectionEpoll.register (Serversocket.fileno (), select. Epollin)#The dictionary that holds the connection client message in the format {}Message_queues = {}    #The file handle to the dictionary of the corresponding object, in the format {handle: Object}Fd_to_socket ={Serversocket.fileno (): ServerSocket,} num=0 whileTrue:Print "wait for active connection ..."        #Polls the registered event collection with a return value of [(File handle, corresponding event), (...),....]Events =Epoll.poll (Timeout)if  notEvents:Print "epoll Timeout No active connection, re -polling ..."            Continue        Print "have a", Len (events),"a new event to begin processing ..."         forFD, EventinchEvents:Print 'FD and event:', FD, event socket=FD_TO_SOCKET[FD]#if the active socket is the current server socket, indicates a new connection            Print 'socket and ServerSocket:', socket, ServerSocketPrint '----------Event & Select. Epollin:', Event &Select. EpollinifSocket = =serversocket:connection, Address= Serversocket.accept ()#connection New Socket object                Print "New Connection:", Address#New Connection socket set to non-blockingconnection.setblocking (False)#registering a new connection FD to the collection of events to be readEpoll.register (Connection.fileno (), select. Epollin)#Save the new connected file handle and the object to the dictionaryFd_to_socket[connection.fileno ()] =Connection#The new connected object is the key value, the value is stored in the queue, and the information for each connection is savedMessage_queues[connection] =Queue.queue ()#Close Event            elifEvent &Select. Epollhup:Print 'Client Close'                #to unregister a client's file handle in EpollEpoll.unregister (FD)#close the client's file handlefd_to_socket[fd].close ()#Delete information related to closed clients in the dictionary                delFD_TO_SOCKET[FD]#Readable Events            elifEvent &Select. Epollin:#Receive Datadata = SOCKET.RECV (1024)                ifData:Print "received data:", data,"Client:", Socket.getpeername ()#to put data into the corresponding client's dictionarymessage_queues[socket].put (data)#Modify the read-to-message connection to the wait-write event collection (that is, the corresponding client receives the message and then modifies its FD and joins the Write event collection)epoll.modify (FD, select. epollout) Num=0Else:                    Print '-------Client close connect or send null data-----------'epoll.modify (FD, select. Epollhup)#Client closes the connection            #Writable Events            elifEvent &Select. Epollout:Try:                    #get the corresponding client information from the dictionarymsg =message_queues[socket].get_nowait ()exceptQueue.empty:PrintSocket.getpeername (),"Queue Empty"                    #modify file handle as read eventepoll.modify (FD, select. Epollin)Else:                    Print "Send data:", data,"Client:", Socket.getpeername ()#Send Datasocket.send (msg)#to unregister a server-side file handle in EpollEpoll.unregister (Serversocket.fileno ())#Close Epollepoll.close ()#shutting down the server socketServersocket.close ()

Client:

#!/usr/bin/env python#-*-coding:utf-8-*-ImportSocket#creating a Client socket objectClientsocket =Socket.socket (Socket.af_inet,socket. SOCK_STREAM)#server-side IP address and port number tupleServer_address = ('127.0.0.1', 6666)#Client Connection Specifies the IP address and port numberClientsocket.connect (server_address) whileTrue:#input Datadata = Raw_input ('Please input:')    #client sends dataclientsocket.sendall (data)#Client receives dataServer_data = CLIENTSOCKET.RECV (1024)    Print 'data received by the client:', Server_data#close the client socket    #clientsocket.close ()

Python epoll for network programming IO multiplexing

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.