Basic Server/Client socket pair not working

Jp Calderone exarkun at divmod.com
Tue Aug 30 00:10:22 CEST 2005


On Mon, 29 Aug 2005 21:30:51 +0200, Michael Goettsche <mail at tuxipuxi.org> wrote:
>Hi there,
>
>I'm trying to write a simple server/client example. The client should be able
>to send text to the server and the server should distribute the text to all
>connected clients. However, it seems that only the first entered text is sent
>and received. When I then get prompted for input again and press return,
>nothing gets back to me. Any hints on what I have done would be very much
>appreciated!

You aren't handling readiness notification properly.  Twisted is a good way to not have to deal with all the niggling details of readiness notification.  I haven't trotted out this example in a while, and it's /almost/ appropriate here ;) so...

http://www.livejournal.com/users/jcalderone/2660.html

Of course, that's highly obscure and not typical of a Twisted application.  Nevertheless, I believe it satisfies your requirements.  You might want to take a look at http://twistedmatrix.com/projects/core/documentation/howto/index.html for a gentler introduction, though.  In particular, the client and server HOWTOs.

I'll comment on your code below.

>
>Here's my code:
>
>############ SERVER ##########
>import socket
>import select
>
>mySocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
>mySocket.bind(('', 11111))
>mySocket.listen(1)
>
>clientlist = []
>
>while True:
>   connection, details = mySocket.accept()
>   print 'We have opened a connection with', details
>   clientlist.append(connection)
>   readable = select.select(clientlist, [], [])
>   msg = ''
>   for i in readable[0]:

You'll need to monitor sockets for disconnection.  The way you do this varies between platforms.  On POSIX, a socket will become readable but reading from it will return ''.  On Win32, a socket will show up in the exceptions set (which you are not populating).  With the below loop, your server will go into an infinite loop whenever a client disconnects, because the chunk will be empty and the message will never get long enough to break the loop.

>      while len(msg) < 1024:
>         chunk = i.recv(1024 - len(msg))
>         msg = msg + chunk

Additionally, select() has only told you that at least /one/ recv() call will return without blocking.  Since you call recv() repeatedly, each time through the loop after the first has the potential to block indefinitely, only returning when more bytes manage to arrive from the client.  This is most likely the cause of the freezes you are seeing.  Instead, call recv() only once and buffer up to 1024 (if this is really necessary - I do not think it is) over multiple iterations through the outermost loop (the "while True:" loop).

>
>   for i in clientlist:
>      totalsent = 0
>      while totalsent < 1024:
>         sent = i.send(msg)
>         totalsent = totalsent + sent

This isn't quite right either - though it's close.  You correctly monitor how much of the message you have sent to the client, since send() may not send the entire thing.  However there are two problems.  One is trivial, and probably just a think-o: each time through the loop, you re-send `msg', when you probably meant to send `msg[totalsent:]' to avoid duplicating the beginning of the message and losing the end of it.  The other problem is that the send() call may block.  You need to monitor each socket for write-readiness (the 2nd group of sockets to select()) and only call send() once for each time a socket appears as writable.

>
>############## CLIENT ################
>import socket
>import select
>
>socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
>socket.connect(("127.0.0.1", 11111))
>
>while True:
>    text = raw_input("Du bist an der Reihe")
>    text = text + ((1024 - len(text)) * ".")
>    totalsent = 0
>    while totalsent < len(text):
>        sent = socket.send(text)
>        totalsent = totalsent + sent

Similar problem here as in the server-side send() loop - `send(text[totalsent:])' instead of sending just `text'.

>
>    msg = ''
>    while len(msg) < 1024:
>        chunk = socket.recv(1024 - len(msg))
>        msg = msg + chunk

This is problematic too, since it means you will only be able to send one message for each message received from the server, and vice versa.  Most chat sessions don't play out like this.

>
>    print msg

I encourage you to take a look at Twisted.  It takes care of all these little details in a cross-platform manner, allowing you to focus on your unique application logic, rather than solving the same boring problems that so many programmers before you have solved.

Hope this helps,

Jp



More information about the Python-list mailing list