faqts : Computers : Programming : Languages : Python : Snippets

+ Search
Add Entry AlertManage Folder Edit Entry Add page to http://del.icio.us/
Did You Find This Entry Useful?

4 of 4 people (100%) answered Yes
Recently 2 of 2 people (100%) answered Yes

Entry

Threading and timeouts

Nov 22nd, 2008 01:27
John Martin, Gaje Pavlin, Nathan Wallace, Hans Nowak, Snippet 331, Phil Mayes


"""
Packages: networking.sockets
"""
"""
>Are timeouts possible inside threads?
>
>Eg: escaping from an attempt to use smtplib.SMTP().sendmail() inside a
>child thread if the remote host is being extremely slow.
>
>It doesn't seem possible to use the traditional signal(SIG_ALRM,...)
>approach because signals only work inside the main thread.
>
>The only option I can think of is to re-write the smtplib module to use
>`select', but does anyone know of a simpler solution?
I struggled with this for some time, failed to get plain old timeouts
working, and ended up with a timeout_socket.py that uses select,
based on code from Lloyd Zusman <[email protected]>.  I then take advantage
of smtplib.py and poplib.py by inheriting:
"""
import poplib, smtplib
class timeout_POP3(poplib.POP3):
    def __init__(self, host, port = poplib.POP3_PORT):
        self.host = host
        self.port = port
        self.sock = timeout_socket.timeout_socket()
        self.sock.connect(self.host, self.port)
        self.file = self.sock.makefile('rb') # same as poplib.POP3
        self._debugging = 0
        self.welcome = self._getresp()
class timeout_SMTP(smtplib.SMTP):
    def connect(self, host='localhost', port = 0):
        """Connect to a host on a given port.
        Override the std SMTP connect in order to use a timeout_socket.
        """
        if not port:
            i = string.find(host, ':')
            if i >= 0:
                host, port = host[:i], host[i+1:]
                try: port = string.atoi(port)
                except string.atoi_error:
                    raise socket.error, "nonnumeric port"
        if not port: port = smtplib.SMTP_PORT
        self.sock = timeout_socket.timeout_socket()
        if self.debuglevel > 0: print 'connect:', (host, port)
        self.sock.connect(host, port)
        (code,msg)=self.getreply()
        if self.debuglevel >0 : print "connect:", msg
        return (code,msg)
"""
This allows me to use poplib.py & smtplib.py unchanged.
The timeout_socket class follows.  I run on Win9x and have a vague
feeling that this won't run on Unix which is why I didn't publish it
before.  If you find out why, yell!
"""
# [PSST NOTE] The following is best extracted as a separate module
# 'timeout'.
#------------ code start ----------------------
""" timeout socket class for connections that can potentially cause
    the server to hang
"""
import socket
import errno
import select
import string
#import appstate  # see comment below
_TIMEOUT = 20.0
class Timeout(Exception):
    pass
class Closing(Exception):
    pass
class timeout_socket:
    def __init__(self, timeout=_TIMEOUT, s=None):
        self.timeout = timeout
        self.inbuf = ''
        if s == None:
            s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.s = s
        self.s.setblocking(0)
    # destructor notes: socket.socket will close when destroyed
    def connect(self, host, port):
        timeout = self.timeout
        s = self.s
        try:
            # Non-blocking mode
            s.setblocking(0)
            s.connect(host,port)
            s.setblocking(timeout != 0)
            return 1
        except socket.error,why:
            # The exception arguments can be (string) or (int,string)
            if len(why.args) == 1:
                code = 0
            else:
                code,why = why
            if timeout:
                s.setblocking(1)
                if code in (errno.EINPROGRESS, errno.EALREADY, 
                errno.EWOULDBLOCK):
                    # Ok, then wait...
                    r,w,e = select.select([],[s],[],timeout)
                    if w:
                        try:
                            s.connect(host, port)
                            return 1
                        except socket.error,why:
                            # This can throw string or (int,string)
                            if len(why.args) == 1:
                                code = 0
                            else:
                                code,why = why
                            if code == errno.EISCONN:
                                return 1
        except:
            code = 0
            why = 'Unknown error trying to connect'
        # format the error message
        if code:
            code = 'error %d = ' % code
        else:
            code = ''
        msg = 'Connect to %s timed out after %d sec (%s%s)' % (host,
         int(self.timeout), code, why)
        raise Timeout, msg
    def send(self, data, timeout=0):
        next = 0
        t = timeout or self.timeout
        total = len(data)
        while 1:
            if appstate.state > appstate.running:
                raise Closing, 'closing'
            r,w,e = select.select([],[self.s], [], t)
            if w:
                buf = data[next:next+8192]
                sent = self.s.send(buf)
                next = next + sent
                if next == total:
                    return
            else:
                raise Timeout, 'timeout while sending "%.20s...": %d sec' %\
                (data, int(t))
    def recv(self, amt, timeout=0):
        t = timeout or self.timeout
        r,w,e = select.select([self.s], [], [], t)
        if r:
            recvd = self.s.recv(amt)
            return recvd
        if not hasattr(self,'s'): 
            print 'timeout_socket has no socket s?!',self.s #TMP - Sam's
problem 9/21
        raise Timeout, "timeout while receiving from %s: %d sec" % (
        `self.s.getpeername()`, int(timeout))
    def recvpending(self, timeout=0):
        """ returns 1/0 """
        return [] != select.select([self.s], [], [], timeout or
self.timeout)[0]
    def read(self, amt):
        """ This only returns when amt has been read or socket times out
"""
        # new version works with readline (except this doesn't convert
CRLF => LF)
        while 1:
            if appstate.state > appstate.running:
                raise Closing, 'closing'
            if len(self.inbuf) >= amt:
                break
            self.inbuf = self.inbuf + self.recv(4096)
        data = self.inbuf[:amt]
        self.inbuf = self.inbuf[amt:]
        return data
    # new readline buffers data
    # this -isn't- called for the makefile clone
    def readline(self):
        while 1:
# useful but non-generic code:
#            if appstate.state > appstate.running:
#                raise Closing, 'closing'
            crlf = string.find(self.inbuf, '\r\n')
            if crlf >= 0:
                break
            self.inbuf = self.inbuf + self.recv(4096)
        data = self.inbuf[:crlf] + '\n'
        self.inbuf = self.inbuf[crlf+2:]
        return data
    def close(self):
        self.s.close()
    def makefile(self, flags):
        self.s.setblocking(1) # s is a socket._socketobject
        save = self.s._sock   # stash the real thing
        self.s._sock = self   # replace it by us
        # this call creates a _fileobject that has been passed self as
the socket
        x = self.s.makefile(flags)
        self.s._sock = save   # restore the real socket
        return x
#------------ code end ------------------------
http://www.webs4soft.com/Links4.htm
http://hotelsinindia.webs4soft.com/hotels-in-delhi.htm
http://indiatravel.webs4soft.com/Resources.htm
http://indianmovies.webs4soft.com/Kuch-Kuch-Hota-Hai.htm
http://real-estate.webs4soft.com/property-tips.htm
http://foodhealthcaretips.webs4soft.com/Resources.htm
http://www.websitecompanyindia.com/seo-Links.htm
http://www.websitecompanyindia.com/seo-Links.htm
http://indianjewelry.websitecompanyindia.com/dimond-ring.htm
http://www.bestindiaeducation.com/Link-Exchange.htm
http://bestjobconsultant.bestindiaeducation.com/PARTNERS.htm
http://eloctronicandmobilestore.bestindiaeducation.com/mobile-links.htm
http://easyloanservice.bestindiaeducation.com/Home-Insurance-Links.htm
http://www.rajhealthcenter.com/Cosmetic-Surgery.htm
http://creativebusinessgroup.rajhealthcenter.com/Business-Links.htm
http://onlinefreeinternetgames.rajhealthcenter.com/Games-Links.htm
http://top-beauty-tips.rajhealthcenter.com/Beauty-Links.htm
http://www.indiatourpoint.com/Travel-Links.htm
http://four-wheeler-buy-tips.indiatourpoint.com/Auto-Links.htm
http://watch-online-free-cricket-match.indiatourpoint.com/Sports-Links.htm
http://directory.indiatourpoint.com/
http://www.bestlifeindia.com/Resources1.htm
http://directory.bestlifeindia.com/
http://freeorkutscrapandsms.bestlifeindia.com/SMS-Links.htm
http://onlinegiftshop.bestlifeindia.com/Gift-Links.htm
http://www.freemusicpoint.com/Music-Links.htm
http://love-dating.freemusicpoint.com
http://online-art-presentation.freemusicpoint.com/
http://onlinefurnitureshop.freemusicpoint.com/