This recipe wraps socketpair() to provide a standard socket pair on POSIX systems or a pair of connected sockets using ephemeral ports on Windows.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
from socket import * import threading try: pairfamily = AF_UNIX except NameError: pairfamily = AF_INET def SocketPair(family=pairfamily, type_=SOCK_STREAM, proto=IPPROTO_IP): """Wraps socketpair() to support Windows using local ephemeral ports""" try: sock1, sock2 = socketpair(family, type_, proto) return (sock1, sock2) except NameError: listensock = socket(family, type_, proto) listensock.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1) listensock.bind( ('localhost', 0) ) iface, ephport = listensock.getsockname() listensock.listen(1) sock1 = socket(family, type_, proto) connthread = threading.Thread(target=pairConnect, args=[sock1, ephport]) connthread.setDaemon(1) connthread.start() sock2, sock2addr = listensock.accept() listensock.close() return (sock1, sock2) def pairConnect(sock, port): sock.connect( ('localhost', port) )
During the development of a recent project, the need arose to handle threads and IPC in a manner that is supported under both POSIX and Windows. Since the threads were part of a network server, the solution presented itself in the form of select.select() and socket pairs. The threads could block in select() while waiting for events from the client socket or notification, via the socket pair, from other threads. However, windows doesn't support socket.socketpair() or AF_UNIX sockets, so I wrote this wrapper.