简体   繁体   中英

How exactly does registering and selecting a socket work?

I'm learning some networking with Python. While I find a lot of code samples, I don't find any explanations for some pieces of code. In the selectors module there seem to be two important functions, register and select. I can't find a good explanation on what exactly they do so I was hoping someone here could help.

As an example I played around a bit with some sample code from the python documentation at https://docs.python.org/3/library/selectors.html . This code sample ends with

sel.register(sock, selectors.EVENT_READ, accept)

while True:
events = sel.select()
for key, mask in events:
    callback = key.data
    callback(key.fileobj, mask)

where "accept" is a function defined elsewhere in the code and "sel" is a selector. I've noticed that at first the select() call blocks the code until a connection is made by a client. But what exactly does it return? From some experiments it seems to return a list with an item for each registered socket that got updated. But what is the "mask" variable? In the python documentation it says that it is "a bitmask of events ready on this file object" , but I have no idea what this means and in my experiments it seems to be just the value 1.

Also, when I replace the for-loop by "print(events)", I notice that once the socket gets used, the code no longer waits every time at sel.select(). Why is this?

When registering a socket, I don't understand the data argument. The documentation just says it is an "opaque object" and it's None by default. Here it seems to be the function that should be called when a socket is used, but is this always the case? And just to be clear, the selectors.EVENT_READ argument indicates that the socket can only receive information, not send it, right?

Thanks in advance for your help!

I've noticed that at first the select() call blocks the code until a connection is made by a client.

More accurately, it blocks until one or more of the registered sockets matches one of its registered events. So, in your example, select() will block indefinitely (since you are not specifying a value for the timeout parameter) until sock reports the EVENT_READ event is ready.

But what exactly does it return? From some experiments it seems to return a list with an item for each registered socket that got updated. But what is the "mask" variable?

This is answered in the same document you linked to:

This returns a list of (key, events) tuples , one for each ready file object.

key is the SelectorKey instance corresponding to a ready file object. events is a bitmask of events ready on this file object.

In the python documentation it says that it is "a bitmask of events ready on this file object", but I have no idea what this means

You can register multiple events for a socket. The reported mask will tell you which of those events is actually ready.

and in my experiments it seems to be just the value 1.

That is the numeric value for EVENT_READ . That is the only value you are getting, because that is the only event you are registering. But there are other events you can register, such as EVENT_WRITE .

Also, when I replace the for-loop by "print(events)", I notice that once the socket gets used, the code no longer waits every time at sel.select(). Why is this?

Because you are not calling your accept() function anymore to read data from the socket. The socket will remain in a readable state as long as it has pending data waiting to be read. Thus your select() will continue to report that EVENT_READ is ready for the socket until all of its pending data has been read.

When registering a socket, I don't understand the data argument.

It is whatever you want it to be. You can associate whatever custom data you want with your event registrations, and then select() will give that data back to you each time an event is reported.

The documentation just says it is an "opaque object" and it's None by default. Here it seems to be the function that should be called when a socket is used, but is this always the case?

No. It can be whatever you need it to be.

And just to be clear, the selectors.EVENT_READ argument indicates that the socket can only receive information, not send it, right?

No. It means that you are interested in being notified only when the socket is in a readable state. You can always write to a socket, at least until shutdown(SHUT_WR) or close() is called on it. For a non-blocking socket, send() can fail if it would block (because the receiver's buffer is full), in which case you would have to wait for EVENT_WRITE to be ready on the socket (the receiver is ready to receive more data) before you can send data on that socket again.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM