[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. 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)