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 ""
?
If successful, recv() returns the length of the message or datagram in bytes. The value 0 indicates the connection is closed.
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.
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.
recv(1024) will read at most 1024 bytes, blocking if no data is waiting to be read.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With