[Zope] Re: Running more than one instance on windows often block
each other
Sune B. Woeller
sune at syntetisk.dk
Fri Jul 29 17:05:23 EDT 2005
Tim Peters wrote:
> [Tim]
>
>>...
>>At this point, I wouldn't consider using it [SO_EXCLUSIVEADDRUSE]
>>unless someone first took the tedious time it needs to demonstrate that
>>when it is used, the thing that _I_ think is a bug here goes away in its
>>presence: the seeming ability of Windows to sometimes permit more
>>than one socket to bind to the same address simultaneously (not serially --
>>Windows does seem to prevent that reliably).
>
>
> I started, but didn't get that far. The first time I ran a pair of
> processes with the attached (Python 2.4.1, WinXP Pro SP2), one fell
> over with
>
> ...
> w.connect((host, port))
> File "<string>", line 1, in connect
> socket.error: (10048, 'Address already in use')
>
> after about 20 minutes.
>
> So, on the face of it, playing with SO_EXCLUSIVEADDRUSE is no better
> than the ZODB 3.4 Windows socket dance. Both appear mounds
> better-behaved than the Medusa Windows socket dance without
> SO_EXCLUSIVEADDRUSE, though. Since there are fewer other problems
> associated with the ZODB 3.4 version (see last email), I'd like to
> repeat this part:
>
>
>>If you can, I would like you to try the ZODB 3.4 Windows socket dance
>>code, and see if it works for you in practice. I know it's not
>>bulletproof, but it's portable across all flavors of Windows and is
>>much better-behaved in my tests so far than the Medusa Windows socket
>>dance.
>
>
> Bulletproof appears impossible due to what still look like race bugs
> in the Windows socket implementation.
I agree that SO_EXCLUSIVEADDRUSE is not interesting - I was too focused on what
I thougth was an error (See the previous posts ).
After your first post I changed select_trigger.py of medusa in my zope
installation to work like the ZODB 3.4 code (like the ZODB svn trunk). The
problem I had with blocks during accept() is not appearing, and my zopes are
running fine.
Tests:
A)
socktest111 on win2k:
It runs fine for more than 3 hours, but a few (1 out of 100) exceptions on
bind() (a printed x) appears.
B)
socktest15 on my winxp home sp2
With SO_EXCLUSIVEADDRUSE:
Has been running for 4 hours without problems.
Needs ports down to around 19800.
Without SO_EXCLUSIVEADDRUSE:
it fails after very
few cycles, (just like socktest111) like this:
. . . .
Traceback (most recent call last):
File "peters2.py", line 72, in ?
stuff = socktest15()
File "peters2.py", line 33, in socktest15
w.connect((host, port))
File "<string>", line 1, in connect
socket.error: (10061, 'Connection refused')
(The old problem. I can't reproduce it on other machines.)
C)
socktest15 on win2k:
With SO_EXCLUSIVEADDRUSE:
Runs fine for more than 3 hours, needs ports down to around 19800
I did not get an "Address already in use" in that amount of time.
Without SO_EXCLUSIVEADDRUSE:
Runs fine for more than 3 hours, needs usually only to go down to 19998
I have not yet been able to get access to the machines for a longer period.
As said above socktest111 and socktest15 (without SO_EXCLUSIVEADDRUSE) fails
immediately on my own machine, so I have not yet been able to reproduce the
processes swapping connection (the failing assert).
D)
socktest2 on my winxp home sp2:
Have run it several times.
Fails after a varying amount of time (2-15 minuttes) with an (10048, 'Address
already in use') in connect. (Just like you experienced). Sometimes both
processes fail at the same time, sometimes only one of them.
C) socktest29
Will try to run that now, and let run a while.
>
> Here's the code. Note that it changed to try (no more than) 10,000
> ports, although I didn't see it need to go through more than 200:
>
> import socket, errno
> import time, random
>
> class BindError(Exception):
> pass
>
> def socktest15():
> """Like socktest1, but w/o pointless blocking games.
> Added SO_EXCLUSIVEADDRUSE to the server socket.
> """
>
> a = socket.socket()
> w = socket.socket()
>
> a.setsockopt(socket.SOL_SOCKET, socket.SO_EXCLUSIVEADDRUSE, 1)
> # set TCP_NODELAY to true to avoid buffering
> w.setsockopt(socket.IPPROTO_TCP, 1, 1)
> # tricky: get a pair of connected sockets
> host = '127.0.0.1'
> port = 19999
>
> while 1:
> try:
> a.bind((host, port))
> break
> except:
> if port <= 10000:
> raise BindError, 'Cannot bind trigger!'
> port -= 1
>
> port2count[port] = port2count.get(port, 0) + 1
> a.listen(1)
> w.connect((host, port))
> r, addr = a.accept()
> a.close()
>
> return (r, w)
>
> def close(r, w):
> for s in r, w:
> s.close()
> return # the fancy stuff below didn't help or hurt
> for s in w, r:
> s.shutdown(socket.SHUT_WR)
> for s in w, r:
> while 1:
> msg = s.recv(10)
> if msg == "":
> break
> print "eh?!", repr(msg)
> for s in w, r:
> s.close()
>
> port2count = {}
>
> def dump():
> print
> items = port2count.items()
> items.sort()
> for pair in items:
> print "%5d %7d" % pair
>
> sofar = []
> i = 0
> try:
> while 1:
> if i % 1000 == 0:
> dump()
> i += 1
> print '.',
> try:
> stuff = socktest15()
> except RuntimeError:
> raise
> sofar.append(stuff)
> time.sleep(random.random()/10)
> if len(sofar) == 50:
> tup = sofar.pop(0)
> r, w = tup
> msg = str(random.randrange(1000000))
> w.send(msg)
> msg2 = r.recv(100)
> assert msg == msg2, (msg, msg2, r.getsockname(), w.getsockname())
> close(r, w)
> except KeyboardInterrupt:
> for tup in sofar:
> close(*tup)
> _______________________________________________
> Zope maillist - Zope at zope.org
> http://mail.zope.org/mailman/listinfo/zope
> ** No cross posts or HTML encoding! **
> (Related lists -
> http://mail.zope.org/mailman/listinfo/zope-announce
> http://mail.zope.org/mailman/listinfo/zope-dev )
>
More information about the Zope
mailing list