Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

recv() in Python

Tags:

python

sockets

open_sockets = []

listening_socket = socket.socket( socket.AF_INET, socket.SOCK_STREAM )

listening_socket.bind( ("", 1234) )

listening_socket.listen(5)

while True:
    rlist, wlist, xlist = select.select( [listening_socket] + open_sockets, [], [] )
    for i in rlist:
        if i is listening_socket:
            new_socket, addr = listening_socket.accept()
            open_sockets.append(new_socket)
        else:
            data = i.recv(1024)
            if data == "":
                i.close()
                open_sockets.remove(i)
                print "Connection closed"
            else:
                i.send(data)
                print repr(data)

Now I know this is simple server code that can handle a few clients - the only thing that I don't understand are these two lines:

        data = i.recv(1024)
        if data == "":

I understand that when the client has already accepted it will go to the other option, the option that checks if there is something in the buffer. I didn't understand why, when there is nothing in the buffer, it goes on and doesn't check the line:

if data == "":

but when the client just presses enter which is equivalent to "" it disconnects

Why when nothing is pressed it is not the same as ""?

like image 597
user1779374 Avatar asked Dec 07 '12 22:12

user1779374


People also ask

What does recv () return?

If successful, recv() returns the length of the message or datagram in bytes. The value 0 indicates the connection is closed.

Is recv () a blocking call?

recv(IPC, Buffer, int n) is a blocking call, that is, if data is available it writes it to the buffer and immediately returns true, and if no data is available it waits for at least n seconds to receive any data.

What is receive function in Python?

Unlike send(), the recv() function of Python's socket module can be used to receive data from both TCP and UDP sockets. The example client and server programs given here for UDP, use recv() at both client and the server sides.

What is Conn RECV 1024?

recv(1024) will read at most 1024 bytes, blocking if no data is waiting to be read.


2 Answers

It starts with the select call. This function watches sets sockets and waits for something noteworthy to happen. For sockets in the first list, "noteworthy" means that the socket has data available for reading.

rlist, wlist, xlist = select.select( [listening_socket] + open_sockets, [], [] )

The code now iterates through the list of sockets with data ready for reading, and acts based on the type of socket being handled.

    for i in rlist:
        if i is listening_socket:

Connection-oriented ("listening") sockets are used to accept new connections. Since it's in rlist, we know it has something for us to "read". In the context of a listening sockets, this means that a new connection has been received. So we accept the connection, and save the new socket in the list of open_sockets.

            new_socket, addr = listening_socket.accept()
            open_sockets.append(new_socket)

If the socket is not listening_socket, then it's a socket which is (or was) connected to a remote client. And again since it's in rlist, we know that it has something for us to "read". In the context of connected sockets, this means either that data is actually available to be read, or that the socket has been closed.

So we call recv to get any available data,

        else:
            data = i.recv(1024)

and see if we've actually read anything. If no data was available, then the connection must have been closed, so we close the socket object and remove it from open_sockets.

            if data == "":
                i.close()
                open_sockets.remove(i)
                print "Connection closed"

If we actually did receive data, we just write it back to the client and print it on the screen.

            else:
                i.send(data)
                print repr(data)

The first call to select will wait until a connection is received. You can see for yourself by updating the code as

print "About to call select"
rlist, wlist, xlist = select.select( [listening_socket] + open_sockets, [], [] )
print "Returned from select"

After the first call, rlist will include listening_socket. We know this because open_sockets is empty, and as called select will not return until something is read to 'read'. So we accept the new connection and add it to open_sockets.

When select is called again, there are three possible events. First, listening_socket might have received another connection. In this case it is handled as before: we accept the connection and add it to open_sockets.

Second, the new connection could have received data. Since select included it in rlist, we know there is data ready to be "read" from the socket (meaning that data is ready for reading, or the socket has been closed). i.recv will return the new data.

Third, the new connection could have been closed. Since select included it in rlist, we know there is data ready to be read from the socket (with the same meaning as above). But i.recv will return "" since the socket doesn't have any new data. So we know the socket has been closed, and clean up accordingly.

If no data is sent from the client (and the connection is still open), then select will not include it in rlist. So the loop will not process it, and i.recv won't be called on that particular socket.

like image 102
GargantuChet Avatar answered Sep 20 '22 18:09

GargantuChet


When a socket sends "" in response, that generally means the socket is closed (or shutdown?). Someone correct me if I'm wrong here. Without that statement, it could become caught in an infinite loop if the remote server suddenly stops responding.

like image 25
Anorov Avatar answered Sep 18 '22 18:09

Anorov