sockets -- basic udp client

7

7stud

My question pertains to this example:

#!/usr/bin/env python

import socket, sys, time

host = sys.argv[1]
textport = sys.argv[2]

s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
try:
port = int(textport)
except ValueError:
# That didn't work. Look it up instread.
port = socket.getservbyname(textport, 'udp')

s.connect((host, port))
print "Enter data to transmit: "
data = sys.stdin.readline().strip()
s.sendall(data)
s.shutdown(1)
print "Looking for replies; press Ctrl-C or Ctrl-Break to stop."
while 1:
buf = s.recv(2048)
if not len(buf):
break
print "Received: %s" % buf


As far as I can tell, the if statement:

if not len(buf):
break

does nothing. Either recv() is going to read some data or it's going
to block. My understanding is that udp sockets do not have a
connection, so the server can't close the connection--hich would cause
a blank string to be sent to the client.

So, as far as I can tell, the only way that code would make sense is
if the server were programmed to send a blank string to the client
after it sent data to the client. Is that correct?
 
G

Gabriel Genellina

My question pertains to this example:

#!/usr/bin/env python

import socket, sys, time

host = sys.argv[1]
textport = sys.argv[2]

s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
try:
port = int(textport)
except ValueError:
# That didn't work. Look it up instread.
port = socket.getservbyname(textport, 'udp')

s.connect((host, port))
print "Enter data to transmit: "
data = sys.stdin.readline().strip()
s.sendall(data)
s.shutdown(1)
print "Looking for replies; press Ctrl-C or Ctrl-Break to stop."
while 1:
buf = s.recv(2048)
if not len(buf):
break
print "Received: %s" % buf


As far as I can tell, the if statement:

if not len(buf):
break

does nothing. Either recv() is going to read some data or it's going
to block. My understanding is that udp sockets do not have a
connection, so the server can't close the connection--hich would cause
a blank string to be sent to the client.

So, as far as I can tell, the only way that code would make sense is
if the server were programmed to send a blank string to the client
after it sent data to the client. Is that correct?

That example is plain wrong; looks like some TCP code but with SOCK_STREAM
blindy replaced with SOCK_DGRAM. connect, sendall and recv are not used
for UDP; sendto and recvfrom are used instead. There are some examples in
the Demo python directory.
 
7

7stud

En Fri, 15 Feb 2008 20:24:19 -0200, 7stud <[email protected]>  
escribió:


My question pertains to this example:
#!/usr/bin/env python
import socket, sys, time
host = sys.argv[1]
textport = sys.argv[2]
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
try:
    port = int(textport)
except ValueError:
    # That didn't work.  Look it up instread.
    port = socket.getservbyname(textport, 'udp')
s.connect((host, port))
print "Enter data to transmit: "
data = sys.stdin.readline().strip()
s.sendall(data)
s.shutdown(1)
print "Looking for replies; press Ctrl-C or Ctrl-Break to stop."
while 1:
    buf = s.recv(2048)
    if not len(buf):
        break
    print "Received: %s" % buf
As far as I can tell, the if statement:
if not len(buf):
   break
does nothing.  Either recv() is going to read some data or it's going
to block.   My understanding is that udp sockets do not have a
connection, so the server can't close the connection--hich would cause
a blank string to be sent to the client.
So, as far as I can tell, the only way that code would make sense is
if the server were programmed to send a blank string to the client
after it sent data to the client.  Is that correct?

That example is plain wrong; looks like some TCP code but with SOCK_STREAM  
blindy replaced with SOCK_DGRAM. connect, sendall and recv are not used  
for UDP; sendto and recvfrom are used instead. There are some examples in  
the Demo python directory.

En Fri, 15 Feb 2008 20:24:19 -0200, 7stud <[email protected]>  
escribió:


My question pertains to this example:
#!/usr/bin/env python
import socket, sys, time
host = sys.argv[1]
textport = sys.argv[2]
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
try:
    port = int(textport)
except ValueError:
    # That didn't work.  Look it up instread.
    port = socket.getservbyname(textport, 'udp')
s.connect((host, port))
print "Enter data to transmit: "
data = sys.stdin.readline().strip()
s.sendall(data)
s.shutdown(1)
print "Looking for replies; press Ctrl-C or Ctrl-Break to stop."
while 1:
    buf = s.recv(2048)
    if not len(buf):
        break
    print "Received: %s" % buf
As far as I can tell, the if statement:
if not len(buf):
   break
does nothing.  Either recv() is going to read some data or it's going
to block.   My understanding is that udp sockets do not have a
connection, so the server can't close the connection--which would cause
a blank string to be sent to the client.
So, as far as I can tell, the only way that code would make sense is
if the server were programmed to send a blank string to the client
after it sent data to the client.  Is that correct?

That example is plain wrong; looks like some TCP code but with SOCK_STREAM  
blindy replaced with SOCK_DGRAM. connect, sendall and recv are not used  
for UDP; sendto and recvfrom are used instead. There are some examples in  
the Demo python directory.


Yes, I agree it's a poor example--it's from 'Foundations of Python
Network Programming'--but it does 'work'. It also doesn't appear to
be a tcp client that was converted too directly into a udp client
because the previously presented tcp examples are different.

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



Another question I have pertains to the docs here:

getservbyname(servicename[, protocolname])
Translate an Internet service name and protocol name to a port number
for that service. The optional protocol name, if given, should be
'tcp' or 'udp', otherwise any protocol will match.


What does a 'servicename' look like?
 
R

rluse1

----------------------------------------------------------------
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
--------------------------------------------------------------

There is still a problem with your script.

buf = s.recv(2048) should be changed to

buf, addr = s.recvfrom(2048) or
buf = s.recvfrom(2048)[0]

or something like that since recvfrom returns a pair.

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.

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


For getservbyname and its complement, getservbyport, they are talking
about well known protocols like http, ftp, chargen, etc. The
following script is a very simple example:

import socket

print socket.getservbyname('http')

print socket.getservbyname('ftp')
print socket.getservbyname('time')


print socket.getservbyport(80)


- Bob
 
G

Gabriel Genellina

Your analysis looks correct to me. If it were using TCP, an empty string
signals that the other side has closed the connection, but being UDP it
cannot happen (unless the server explicitely sends an empty string, as you
said).
Yes, I agree it's a poor example--it's from 'Foundations of Python
Network Programming'--but it does 'work'. It also doesn't appear to
be a tcp client that was converted too directly into a udp client
because the previously presented tcp examples are different.

Ok, you *can* use those functions with datagrams too, but it's confusing
(at least for the very first UDP example!)
Another question I have pertains to the docs here:

getservbyname(servicename[, protocolname])
Translate an Internet service name and protocol name to a port number
for that service. The optional protocol name, if given, should be
'tcp' or 'udp', otherwise any protocol will match.

What does a 'servicename' look like?

py> import socket
py> socket.getservbyname("http")
80
py> socket.getservbyname("smtp")
25

On Linux the mapping ports<->services is in /etc/services; on Windows see
%windir%\system32\drivers\etc\services
 
7

7stud

----------------------------------------------------------------
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
--------------------------------------------------------------

There is still a problem with your script.

buf = s.recv(2048)  should be changed to

buf, addr = s.recvfrom(2048)  or
buf = s.recvfrom(2048)[0]

or something like that since recvfrom returns a pair.

If you don't care about the address of the sender, e.g. you are not
going to send anything back, is there an advantage to using recv()?
Or, as a matter of course should you always use recvfrom() with udp
sockets?

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.

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

For getservbyname and its complement, getservbyport, they are talking
about well known protocols like http, ftp, chargen, etc.  The
following script is a very simple example:

import socket

print socket.getservbyname('http')

print socket.getservbyname('ftp')
print socket.getservbyname('time')

print socket.getservbyport(80)

 - Bob

Thanks
 
7

7stud

Ok, you *can* use those functions with datagrams too, but it's confusing  
(at least for the very first UDP example!)

Yes, I agree. The book is well written, but the introductory examples
and a lack of explanation of the finer details is a disaster.

Another question I have pertains to the docs here:
getservbyname(servicename[, protocolname])
Translate an Internet service name and protocol name to a port number
for that service. The optional protocol name, if given, should be
'tcp' or 'udp', otherwise any protocol will match.
What does a 'servicename' look like?

py> import socket
py> socket.getservbyname("http")
80
py> socket.getservbyname("smtp")
25

On Linux the mapping ports<->services is in /etc/services; on Windows see  
%windir%\system32\drivers\etc\services

Thanks.
 
R

rluse1

If you don't care about the address of the sender, e.g. you are not
going to send anything back, is there an advantage to using recv()?
Or, as a matter of course should you always use recvfrom() with udp
sockets?


I don't know of a reason why you couldn't use recvfrom() all the time,
and that is what I do. However, I also don't see a reason why you
should
not use recv() if you don't care who the message comes from.
Historically,
though, the ultimate authority on this kind of stuff is

Richard Stevens and his Unix and TCP/IP books

I recommend these books if you want to get into network programming.

Cheers,
Bob
 
P

Paul Rubin

Historically, though, the ultimate authority on this kind of stuff is
Richard Stevens and his Unix and TCP/IP books

I recommend these books if you want to get into network programming.

I keep wanting to get that book, but it gets older and older. Have
things really not changed since it was written?
 
S

Steve Holden

Paul said:
I keep wanting to get that book, but it gets older and older. Have
things really not changed since it was written?

TCP is much like a funicular railway: it's been around long enough that
the basic engineering principles are known and the basic bugs have been
ironed out. Stevens is still an excellent reference.

regards
Steve
 
R

Roy Smith

In article "[email protected] said:
If you don't care about the address of the sender, e.g. you are not
going to send anything back, is there an advantage to using recv()?

At the system call level, recv() is marginally faster since there's less
data to pass back and forth between the kernel and user space. Not that
this is likely to be significant in any real-world application.

The bigger advantage to recv() is that the interface is simpler, so there's
less code to write. For the C interface, using recv() instead of
recvfrom() frees you from having to pass in two arguments that you're not
going to use. From the Python interface, it frees you from having to
unpack the tuple that recvfrom() returns. Instead of:

data, address = recvfrom(bufsize)

you write

data = recv(bufsize)

It's not just a bunch less typing, it's also easier to understand. You
don't leave some future maintainer of your code scratching their head
trying to figure out where 'address' is used, when in fact, it's not.
 
D

Douglas Wells

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
 
7

7stud

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.

Nice catch.
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).

I was hashing through that very issue last night. I was wondering how
sendall() knew where to send the data. The author says this about the
initial UPD example I posted(the one that calls connect()):
...there's no actual connection here. The call to connect()
did nothing but initialize some internal parameters.

I deduced that one such initialization was automatically resolving the
hostname into an ip address. Thanks for the info on another important
one.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,007
Latest member
obedient dusk

Latest Threads

Top