- This talk isn't really about sockets
- (well not entirely)
- now that is cleared up lets get sockets out of the way...
The rather normal network socket:
import socket tcp_socket = socket.socket(socket.AF_INET6, socket.SOCK_STREAM) tcp_socket.connect(("google.com", 80)) tcp_socket.sendall(b"GET / HTTP/1.1\r\n")
- A not so distant cousin to how your browser kicks off a request...
- Let's take a look at the normal client/server example for network sockets
def echo(conn): while True: data = conn.recv(1024) if not data: break conn.send(data) conn.close() def consumer_server(... s = socket.socket(address_family, socket_type, protocol) s.bind( s.listen(5) while True: conn, addr = s.accept() threading.Thread(target=echo, args=(conn,)).start()
- listen(5) tells the OS to queue up to 5 connection requests
- Note a new thread gets spun up for every client connection
- Threads spin up plenty quick
- Yes all the error handling has been removed to ease readability at the expense of all usability..
af, socktype, proto, _, sa = socket.getaddrinfo( host, random_port, socket.AF_UNSPEC, socket.SOCK_STREAM) s = socket.socket(af, socktype, proto) s.connect(sa) s.sendall(outgoingdata)
- Leaving the address family unspecified will return INET and INET6
Meet the Freerunner - open source phone running SHR (debian based)
ssh email@example.com cd code cat server.py python server.py
Well it would be a bit boring just running on my laptop!
Incase I forget run on the pc: python3 basic_socket_client.py
So on GNU/Linux everything is a file. This includes everything from .txt files to Sockets.
TCP/UDP sockets can connect endpoints on the same network
Unix Sockets can only connect endpoints on the same machine.
This lets the Kernel make some assumptions and cut out the
expensive "networking" layer.
They are extensively used for Inter Process Communicaton, including internally in Python's multiprocessing.connection module:
# A higher level module for using sockets (or Windows named pipes) # # multiprocessing/connection.py
- From Python 3.3 Unix Sockets can also be used to send open file descriptors (open files or sockets) to another Process using the sendmsg() and recvmsg() calls.
What if you were running your python program on a cretin system that didn't give you enough memory?
But you knew the kernel had access to plenty more...
You could fire off a socket and use it as some FIFO form of memory storage...
Extremely Contrived Example
- Main thread wants to "save some data" out of process memory by creating a local socket with a large buffer
- the consumer thread just creates the socket/s
- to illustrate the concept my worker thread isn't allowed to access this memory (read from socket) until all the data has been stored
- sha256 on the bytes saved and recalled should match
example socket_memory.py output
Connected by ('127.0.0.1', 45527) waiting for producer to finish filling the socket "Saved" 250 blocks of 2048 random bytes SHA256 of sent: 290491d7b26ab55cf62cf9ea662634b0bd63509dfbaf02877aab458a161a5fd9 okay lets have your data Received 250 x 2048 bytes of data SHA256 of recv: 290491d7b26ab55cf62cf9ea662634b0bd63509dfbaf02877aab458a161a5fd9
- No I'm not really serious, but it did appear to work...
The much awaited Rasberry Pi! + actually I'm still waiting for mine + easily fitted with a USB bluetooth dongle + actually just another computer... + which is a bit boring + need something more fun
iRacer from sparkfun
- on-board Bluetooth radio
- RFCOMM Bluetooth...
- Protocol is dead easy - 0xXY where X is the direction and Y is the speed. E.G 0x16: Direction=Forwards, mid-speed.
One mention of "bluetooth" on the Python 3.3 socket docs... + How hard could it be... + Okay I had to use the source but the end result is easy!
import socket import time class BluetoothCar: def __init__(self, mac_address="00:12:05:XX:XX:XX"): self.socket = socket.socket( socket.AF_BLUETOOTH, socket.SOCK_STREAM, socket.BTPROTO_RFCOMM) self.socket.connect((mac_address, 1)) def forwards(self, duration=1.0): self.drive(0x16, duration) ... def drive(self, command, duration): self.socket.send(bytes([command])) time.sleep(duration) self.socket.send(bytes([0x00]))