Muliplexing Socket Connections

Steve Holden sholden at cox.rr.com
Mon Apr 23 14:00:39 EDT 2001


"Nathan Cassano" <nathan at cjhunter.com> wrote in message
news:3AE465F6.9FDDAD97 at cjhunter.com...
> Hello Pythoneers,
>     I'm developing a socket server that needs to bind to and multiplex
multiple
> ports. I'm using the select module and sockets to do this. The problem is
I
> cannot get the select function to return a file descriptor from it's
return read
> list. Does anyone have a simple example of socket multiplexing or some
pointers?
>
> import socket, select
>
> sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
> sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
> sock.setblocking(0)
>
> print select.select([sock],[sock] ,[] , 0)
>
> ...
>
> This is the output that follows
>
> ([], [<socket object, fd=3, family=2, type=1, protocol=0>], [])
>
The point, surely, is that if select() returns [[], [], []] then it timed
out and there's nothing to do, otherwise why can't you just use operate on
the sockets returned? Since select() returns lists of readable and writable
sockets, you can just iterate over the lists it returns, performing the
indicated operations. Or am I missing something?

Here's a function extracted from a program which needs to find the MX
servers for a particular domain. It's not too elegant as it was very early
on in my Python socket career. Look for the added "##" comments below...

HTH
 Steve

#
# Read dnslib.py if you really need to understand this code,
# which generates a DNS request for MX records and decodes
# the reply using functionality implemented in dnslib.
#
def MXlist(qname, server):
    """Return a list of MX exchangers for a given domain.

    This code is based on the dnslib library, and  is complicated
    by the necessity to handle UDP errors where no response is
    generated by (or at least received from) the remote host."""
    global mxdict       # Cacheing dictionary
    if mxdict.has_key(qname):
        lf.log("[[[ Domain %s MX hosts were cached" % (qname, ))
        return mxdict[qname]
    protocol = 'udp'    # This is bogus: not used anywhere!
    port = 53
    opcode = dnsopcode.QUERY
    rd = 1              # server should recurse
    qtype = dnstype.MX
    m = dnslib.Mpacker()
    m.addHeader(0, 0, opcode, 0, 0, rd, 0, 0, 0, 1, 0, 0, 0)
    m.addQuestion(qname, qtype, dnsclass.IN)
    request = m.getbuf()
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    s.setblocking(0) # We need a non-blocking socket
    s.connect((server, port))
    r, w, e = select.select([s], [s], [s], 15)
##
## Here I seem to assume a valid return means the socket
## is writable ... told you I wasn't proud of the code!
##
    if [r, w, e] == [[], [], []]:
        lf.debug("!!! Connect timed out in MXlist")
        return []
##
## So I just send on it!
##
    s.send(request)
    r, w, e = select.select([s], [s], [s], 15)
    if [r, w, e] == [[], [], []]:
        lf.debug("!!! Send timed out in MXlist")
        return []
##
## Since the socket has now stopped blocking, I think the
## following select is probably completely redundant
##
    r,w,e = select.select([s], [], [], 15.0)
##
## The above call is waiting for the socket to become readable
##
    if r:
        reply = s.recv(2048)
##
## Now it is, I just receive on it
##
    else:
        s.close()
        raise Timeout("Recv timed out in MXlist")
##
## No other return from select() is any use in my case
##
## The rest of the code is irrelevant
##
    u = dnslib.Munpacker(reply)
    (id, qr, opcode, aa, tc, rd, ra, z, rcode,
        qdcount, ancount, nscount, arcount) = u.getHeader()
    for i in range(qdcount):
        qname, qtype, qclass = u.getQuestion()
    MX = []
    for i in range(ancount):
        name, type, klass, ttl, rdlength = u.getRRheader()
        MX.append([u.get16bit(), u.getname()])
    MX.sort()
    servers = []
    for mx in MX:
        servers.append(string.lower(mx[1]))
    s.close()
    mxdict[qname] = servers
    lf.log("[[[ %d candidate mail exchangers for %s: %s" %
                (len(servers), qname, string.join(servers, ", ")))
    return servers





More information about the Python-list mailing list