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 |