What I'll be talking about
Server:
>>> sock = socket(AF_INET6, SOCK_DGRAM)
>>> sock.bind(('', 1055))
>>> data, clientaddr = sock.recvfrom(4096)
>>> data
'request'
>>> clientaddr
('::ffff:127.0.0.1', 39241, 0, 0)
>>> sock.sendto(b'response', clientaddr)
7
>>> sock.close()
>>> del sock
Client:
>>> sock = socket(AF_INET, SOCK_DGRAM)
>>> sock.sendto(b'request', ('127.0.0.1', 1055))
7
>>> sock.recvfrom(4096)
('response', ('127.0.0.1', 1055))
>>> sock.close()
>>> del sock
Binding to '' is the wildcard.
Use .sendto(), .recvfrom()
udp6 can receive IPv4 connections: ::ffff:n.n.n.n v4 mapped address.
Netstat shows the listening socket after binding:
$ netstat -l -n -A inet,inet6 Active Internet connections (only servers) Proto Recv-Q Send-Q Local Address Foreign Address State udp6 0 0 :::1055 :::*
Sockets not cleaned up when closed
Client:
>>> sock = socket(AF_INET, SOCK_DGRAM)
>>> sock.connect(('127.0.0.1', 1055))
>>> sock.send(b'message')
7
Server:
>>> sock = socket(AF_INET6, SOCK_STREAM)
>>> sock.bind(('', 1055))
>>> sock.listen(SOMAXCONN)
>>> client, addr = sock.accept()
>>> addr
('::ffff:127.0.0.1', 54584, 0, 0)
>>> client.recv(4096)
'message'
>>> client.close()
>>> sock.close()
Client:
>>> sock = socket(AF_INET, SOCK_STREAM)
>>> sock.connect(('127.0.0.1', 1055))
>>> sock.sendall(b'message')
7
>>> sock.close()
$ netstat netstat -n -A inet,inet6 Active Internet connections (w/o servers) Proto Recv-Q Send-Q Local Address Foreign Address State tcp 0 0 127.0.0.1:54584 127.0.0.1:1055 ESTABLISHED tcp6 0 0 127.0.0.1:1055 127.0.0.1:54584 ESTABLISHED
sock = socket() sock.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1) sock.bind(...) ...
getaddrinfo(host, port, family=AF_UNSPEC, socktype=0, proto=0, flags=0) --> [(family, socktype, proto, canonname, sockaddr), ...]
AI_CANONNAME: return canonical name
AI_NUMERICHOST, AI_NUMERICSERV: no lookups
AI_PASSIVE: suitable for listening
AI_ADDRCONFIG: AF has configured interface
AI_V4MAPPED, AI_ALL: return v4 addrs when asking AF_INET6
Be as explicit as possible:
getaddrinfo('example.com', 80, AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP, AI_ADDRCONFIG)
In practice just see what works (client):
ai_list = socket.getaddrinfo('example.com', 80, 0, SOCK_STREAM) err = None for af, socktype, proto, cn, sockaddr in ai_list: sock = None try: sock = socket(af, socktype, proto) sock.connect(sockaddr) except Exception, e: err = e if sock: sock.close() else: break else: raise err if not ai_list: raise error('getaddrinfo returns empty list')
try:
    sock = create_connection(('example.com', 80))
except socket.error as e:
    logging.warn('Failed to create connection: %s', e.strerror)
strerror:
Connection refused Name or service not known ...
Call .setblocking(Flase)
Operations might raise EWOULDBLOCK:
sock = socket()
sock.setblocking(False)
sock.connect(...)
try:
    sock.recv(4096)
except IOError as e:
    if e.errno == errno.EWOULDBLOCK:
       pass
Managing this by had is messy
select(rlist, wlist, xlist[, timeout]) --> (ready_rlist, ready_wlist, ready_xlist)
Graceful interrupting I/O operations:
while keep_running:
    rpipe, wpipe = os.pipe()
    rlist = get_rlist()
    rlist.append(rpipe)
    wlist = get_wlist()
    readable, writable, _ = select.select(rlist, wlist, [], 60)
    if rpipe in readable:
        try:
            os.read(rpipe, 4096)
        except Exception:
            pass
        break
    if readable:
        # handle reads
    if writable:
        # handle writes
def recv(n):
    while True:
        try:
            sock.recv(n)
        except socket.error as e:
            if e.errno == errno.EINTR:
                continue
            else:
                raise
No package boundaries in streams
Example of protocol header (AgentX, RFC 2741):
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | h.version | h.type | h.flags | <reserved> | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | h.sessionID | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | h.transactionID | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | h.packetID | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | h.payload_length | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
"Protocol" layer which wants to send and receive "frames"
Minimal copying of data
Several approaches:
io.BytesIO
C implementation, hard to use thread safe
list of strings
More fragmented memory
bytearray (for fixed size data only)
...
Receiving data, using BytesIO:
class Protocol(object):
    def __init__(self):
        self._rbuf = io.BytesIO()
    def data_received(self, data):
        self._rbuf.seek(0, io.SEEK_END)
        self._rbuf.write(data)
        if self._rbuf.tell() >= 20:
            self._rbuf.seek(0, io.SEEK_SET)
            hdr = self._rbuf.read(20)
            payload_length, = struct.unpack('!L', hdr[16:20])
            payload = self._rbuf.read(payload_length)
            if len(payload) == payload_length:
                tail = self._rbuf.read()
                self._rbuf.seek(0, io.SEEK_SET)
                self._rbuf.truncate()
                self._rbuf.write(tail)
                self.process_frame(hdr + payload)
Sending data:
class Transport(object):
    def __init__(self):
        self._wbuf = []
        self._rpipe, self._wpipe = os.pipe()
    def write(self, data):
        self._wbuf.append(data)
        try:
            os.write(self._wpipe, 'a')
        except Exception:
            pass
    def _send(self, sock):
        buf = self._wbuf
        self._wbuf = []
        data = ''.join(buf)
        try:
            n = sock.send(data)
        except socket.error, e:
            if e.errno not in [errno.EWOULDBLOCK, errno.EINTR]:
                raise
            self._wdata.insert(0, data)
            del data
        else:
            if len(data) > n:
                self._wdata.insert(0, data[n:])
            del data
Client:
>>> sock = socket()
>>> sock.connect(('127.0.0.1', 1055))
>>> sock.send(b'request')
7
>>> sock.shutdown(SHUT_WR)
>>> sock.recv(4096)  # blocks
'response'
Server:
>>> sock = socket(AF_INET6)
>>> sock.bind(('', 1055))
>>> sock.listen(SOMAXCONN)
>>> client, addr = sock.accept()  # blocks
>>> fp = client.makefile()
>>> fp.read(4096)                 # blocks until EOF
'request'
>>> fp.write(b'response')
8
>>> client.close()
>>> del client
Can be used without shutting down the socket ends:
Can be used in non-blocking mode:
(Yes, these all have a particular meaning)
Network methods yield control to the hub:
from eventlet.green.socket import *
sock = socket()
sock.connect(('127.0.0.1', 1055))  # switch to hub
sock.send(b'request')              # switch to hub
Spawning tasks:
def server():
    sock = socket(AF_INET6)
    sock.bind(('', 1055))
    sock.listen(SOMAXCONN)
    while True:
        client, addr = sock.accept()                # switch to hub
        eventlet.spawn(handle_client, client, addr)
def handle_client(sock, addr):
    print('connection from {}'.format(addr))
    req = sock.recv(4096)                           # switch to hub
    sock.send(b'response')                          # switch to hub
No need to do complicated write buffer
| Table of Contents | t | 
|---|---|
| Exposé | ESC | 
| Full screen slides | e | 
| Presenter View | p | 
| Source Files | s | 
| Slide Numbers | n | 
| Toggle screen blanking | b | 
| Show/hide slide context | c | 
| Notes | 2 | 
| Help | h |