server bootstrapping upon connection (WARNING: LONG)

ralf at brainbot.com ralf at brainbot.com
Wed Feb 11 00:22:30 CET 2004


Benjamin Han <this at is.for.spambot> writes:

> On 2004-02-10 13:46:37 -0500, ralf at brainbot.com said:
>
>> fortepianissimo at yahoo.com.tw (Fortepianissimo) writes:
>>> The problem: I need to prevent multiple copies of the server being
>>> started. I did this by using file locking (fcntl.lockf()). However,
>>> not every time the code successfully prevented the server being
>>> started up more than one time. Here is the relevant code:
>> When using fcntl.lockf different FooClient instances in the same
>> process will be able lock the file and start another server. You could
>> either use fcntl.flock to prevent that or use some global flag.
>
> Hm... I didn't know there's a difference between flock() and lockf(),
> and I didn't get much info from the document either. Could you explain
> a bit on why lockf() would not lock the file?

Well, it might lock the file multiple times in the same
process. That's the problem:
----
import fcntl

def getlockfile():
    return open('serverStart.lock', 'w')

def getlock(f):
    try:
        lock(f.fileno(), fcntl.LOCK_EX|fcntl.LOCK_NB)
    except:
        return False
    return True

def doit():
    f1 = getlockfile()
    f2 = getlockfile()
    print getlock(f1), getlock(f2)

lock = fcntl.lockf
doit()

lock = fcntl.flock
doit()
---

Output is:
True True
True False


>
> Actually I wrote a tiny script just to test if lockf() does what it
> claims to do:
>
> --- CODE STARTS ---
> #!/usr/bin/env python
>
> import os,fcntl,sys
>
> print "* about to open flock.txt"
> f=open('flock.txt','w')
> print "* opened the file"
> fcntl.lockf(f.fileno(),fcntl.LOCK_EX|fcntl.LOCK_NB)
> print "* obtained the lock, enter your line below:"
> l=sys.stdin.readline()
> f.truncate()
> f.write(l)
> f.flush()
> sys.stdin.readline()
> f.close()
>
> --- CODE ENDS ---
>
> It seems it does lock the file? (Mac OS X 10.3.2).
>
>> Also be sure to keep the file open by keeping a reference to it
>> (i.e. self.serverStartLock=open(...)). For debugging purposes,
>> remove that 'if self.connect(): return' and
>> I think you'll see much more servers being started.
>
> --- CODE SNIPPET STARTS ---
> class FooClient:
>     def __init__ (self, startServer=True):
>         """Connects to FooServer if it exists, otherwise starts it and
> connects to it"""
>         self.connected=True
>         if self.connect(): return
>         elif not startServer:
>             if FOO_CLIENT_DEBUG: log('connection failed 1')
>             self.connected=False
>             return
> ..
> --- CODE SNIPPET ENDS ---
>
> Well in that case every connection will try to start a server. Good
> point on keeping a reference to the lock file though - I'll add to it
> and see what happens.
>
>>> From the log (when problem occurred) I see even *AFTER* the server
>>> was
>>> started and accepted connections (several connections came and went
>>> happily), a connection would come in and hit the "connection failed 1"
>>> log line. This shouldn't have happened as the default value of
>>> startServer for FooClient.__init__() is True. In the very same
>> Well, maybe too many connection attempts are pending...
>
> I failed to see why this should affect the default value of the
> argument... if startServer is True (default), that log line should
> have never been reached.

Well, then I suppose you're passing an false argument to
FooClient.__init__. I just wanted to say, that even if the server is
listening on that port, that connection attempts may fail.

>
> Thanks!
>
> Ben

-- 
brainbot technologies ag
boppstrasse 64 . 55118 mainz . germany
fon +49 6131 211639-1 . fax +49 6131 211639-2
http://brainbot.com/  mailto:ralf at brainbot.com



More information about the Python-list mailing list