selfboot / AnnotatedShadowSocks

Annotated shadowsocks(python version)
Other
3 stars 1 forks source link

Socket: Non-blocking Communication and Timeouts #14

Open selfboot opened 7 years ago

selfboot commented 7 years ago

By default a socket is configured so that sending or receiving data blocks, stopping program execution until the socket is ready. Calls to send() wait for buffer space to be available for the outgoing data, and calls to recv() wait for the other program to send data that can be read.

When a program uses blocking sockets it often uses one thread (or even a dedicated process) to carry out the communication on each of those sockets. The main program thread will contain the listening server socket which accepts incoming connections from clients. It will accept these connections one at a time, passing the newly created socket off to a separate thread which will then interact with the client. Because each of these threads only communicates with one client, any blockage does not prohibit other threads from carrying out their respective tasks.

This form of I/O operation is easy to understand, but can lead to inefficient operation, because the cost when create or destroy the thread is too much. When the server need to handle thousands of socket, it can be very hard.

There are a few ways to work around this situation. One is to use a separate thread for communicating with each socket. This can introduce other complexities, though, with communication between the threads.

Another option is to change the socket to not block at all, and return immediately if it is not ready to handle the operation. Use the setblocking() method to change the blocking flag for a socket. The default value is 1, which means to block. Passing a value of 0 turns off blocking. If the socket is has blocking turned off and it is not ready for the operation, then socket.error is raised.

A compromise solution is to set a timeout value for socket operations. Use settimeout() to change the timeout of a socket to a floating point value representing the number of seconds to block before deciding the socket is not ready for the operation. When the timeout expires, a timeout exception is raised.

Ref
https://pymotw.com/2/socket/nonblocking.html