In client server applications, when a client makes a request to a server, server processes the request and sends back a response. For this, both the client and the server first needs to establish a connection with one another through sockets (TCP or UDP). In the last few tutorials, we also saw, how a client can send data in form of request to the server and the server can operate on it, and then send a response back to the client.
By default, TCP sockets are placed in a blocking mode. This means that the control is not returned to your program until some specific operation is complete.
For example, if you call the
connect() method, the connection blocks your program until the operation is complete. On many occasions, we don't want to keep our program waiting forever.
Taking another example, when we write a web browser client that connects to a web server, we should consider a stop functionality that can cancel an active connection process in the middle of its operation. This can be achieved by placing the socket in the non-blocking mode.
We can call
setblocking(1) to set up blocking or
setblocking(0) to unset blocking. Let's understand it with the help of an example. First of all, let's consider a Blocking Socket:
#!usr/bin/python import socket sock = socket.socket() host = socket.gethostname() sock.connect((host, 12345)) sock.setblocking(1) # Or simply omit this line as by default TCP sockets # are in blocking mode data = "Hello Python\n" *10*1024*1024 # Huge amount of data to be sent assert sock.send(data) # Send data till true
#!usr/bin/python #block_server.py import socket s = socket.socket() host = socket.gethostname() port = 12345 s.bind((host,port)) s.listen(5) while True: conn, addr = s.accept() # accept the connection data = conn.recv(1024) while data: # till data is coming print data data = conn.recv(1024) print "All Data Received" # Will execute when all data is received conn.close() break
block_server.py first and then
block_client.py. You'll notice that the server keeps on printing Hello Python. This will go on and on till all the data is sent. In the above code the line All Data Received will not be printed for long time, because as the client has to send a large number of string, which will take time, and until then the socket input-output will get blocked.
What's going on here? The
send() method will try to transmit all the data to the server, while the write buffer will get filled up. The kernel will put the process to sleep until the data in the buffer is transferred to the destination and the buffer is empty again. When the buffer becomes empty, the kernel will wake the process up again to get the next chunk of data that is to be transferred. In short, your code will block and it will not let anything else proceed.
Now consider a Non-Blocking Socket
#!usr/bin/python # non_blocking_client.py import socket sock = socket.socket() host = socket.gethostname() sock.connect((host, 12345)) sock.setblocking(0) # Now setting to non-blocking mode data = "Hello Python\n" *10*1024*1024 # Huge amount of data to be sent assert sock.send(data) # Send data till true
Now, if we run the
non_blocking_client.py, you'll notice that the program will run for a small time, it will print the last line "All Data Received" and soon terminate.
What's going on here? Here the client did not send all the data. When we make a socket non-blocking by calling
setblocking(0), it will never wait for the operation to complete. So when we call the
send() method, it will put as much data in the buffer as possible and return.