sockets -- basic udp client

Douglas Wells see at signature.invalid
Sun Feb 17 14:15:21 EST 2008


In article <08e1d06e-821b-4166-9bea-8ba0b488babe at q70g2000hsb.googlegroups.com>,
  "rluse1 at gmail.com" <rluse1 at gmail.com> writes:

I have had some difficulty following the assertions, corrections,
and misquoting in this article thread, so apologies in advance if
I have missed a correction or misunderstood an assertion.

[ quoting partially corrected: ]
>> ----------------------------------------------------------------
>> Here is the example above converted to a more straightforward udp
>> client that isolates the part I am asking about:
>> 
>> import socket, sys
>> 
>> host =  'localhost'  #sys.argv[1]
>> port = 3300
>> s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
>> 
>> data = 'hello world'
>> num_sent = 0
>> while num_sent < len(data):
>>     num_sent += s.sendto(data, (host, port))
>> 
>> print "Looking for replies; press Ctrl-C or Ctrl-Break to stop."
>> while 1:
>>     buf = s.recv(2048)
>> 
>>     #Will the following if statement do anything?
>>     if not len(buf):
>>         break
>> 
>>     print "Received from server: %s" % buf
>> --------------------------------------------------------------

> But, for the specific case that you have asked about, since the
> default for timeout is no timeout, or block forever, your question:
> 
> #Will the following if statement do anything?
>     if not len(buf):
>         break
> 
> The answer is that you are right, it will do nothing.  But, if you set
> a time out on the socket, and you receive no data and the timeout
> expires, checking for the length of zero and a break is one way to
> jump out of the loop if you need to.

That is not correct in my experience.  The test "not len(buf)" --
or perhaps more clearly "len(buf) == 0" is a valid way, perhaps
the preferred way, of detecting a zero length datagram as transmitted
via UDP (socket.SOCK_DGRAM).

Zero length datagrams are perfectly valid in UDP and in fact are
the recommended way of initiating certain protocol actions.  See,
for example, the Time Protocol (RFC 868, top of page 2).

While POSIX regular files and TCP streams use a zero read result
to indicate end-of-file, the action is different for "message-based
sockets" (and STREAMS).  In the case of UDP, there is no concept
of end-of-file, and thus no API mechanism for indicating such.
Instead, the zero return is used to indicate a zero-length message.

Timeouts are indicated by raising an exception:

- In the case of the settimeout method of socket, a socket.timeout
  exception is raised.
- In the case of use of socket option socket.SO_SNDTIMEO, a
  socket.error exception is raised w/ errno = EAGAIN.

> For example:
> 
> import socket, sys
> 
> host =  'localhost'  #sys.argv[1]
> port = 3300
> s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
> 
> s.settimeout(1.0)
> buf = ''
> 
> data = 'hello world'
> num_sent = 0
> 
> while num_sent < len(data):
>     num_sent += s.sendto(data, (host, port))
> 
> print "Looking for replies; press Ctrl-C or Ctrl-Break to stop."
> while True:
> 
>     try:
>         buf, addr = s.recvfrom(2048)
>     except:
>         pass
> 
>     #Will the following if statement do anything?
>     # In this case it will cause the script to jump out of the loop
>     # if it receives no data for a second.
>     if not len(buf):
>         break
> 
>     print "Received from server: %s" % buf

The reason that this example *seems* to work is that you mask the
exception.  What is actually happening is that the timeout of the
recvfrom call raises socket.timeout, which is ignored.  Then because
buf has been explicitly set to zero length (near the beginning of
the program), and because it is *not* modified as a result of the
recvfrom call, the length is still zero, and the break is executed.
Try commenting out the try/except construct, or try actually
providing at least one non-zero length response (such that buf is
modified) and seeing if it ever terminates.

I would also like to point out that the original example (quoted
from the book) used "connect' and "recv" w/ UDP).  One of the
purposes of using this construct (rather than using "recvfrom")
is to simplify identification of the remote system:  When you
"connect" to a UDP socket, the OS will only send messages to that
system and will ignore messages that do not originate from that
IP address (ignoring the issue IP address spoofing).

 - dmw

-- 
.   Douglas Wells             .  Connection Technologies      .
.   Internet:  -sp9804- -at - contek.com-                     .



More information about the Python-list mailing list