Source

python-socket-examples / slideshow.md

Full commit

% Sockets? % Brian Thorne @thorneynz % Kiwi Python Conference 2012

<!-- pandoc -s --highlight-style=pygments --webtex -i -t slidy slideshow.md -o presentation.html -->

Seriously a talk on Sockets?

  • Who the hell would give a talk on sockets?
  • This talk isn't really about sockets
  • (well not entirely)
  • now that is cleared up lets get sockets out of the way...

Network Sockets

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

Server

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

Client

af, socktype, proto, _, sa = socket.getaddrinfo(
    host, 
    random_port, 
    socket.AF_UNSPEC, 
    socket.SOCK_STREAM)[0]
s = socket.socket(af, socktype, proto)
s.connect(sa)
s.sendall(outgoingdata)
  • Leaving the address family unspecified will return INET and INET6
  • This would be a bit of a boring demo (at least running on my laptop)

Neo Freerunner

Meet the Freerunner - open source phone running SHR (debian based)

ssh root@192.168.7.2

cd code
cat server.py
python server.py
  • On the other end (e.g. my pc) run client(s)

    python3 basic_socket_client.py

Unix Sockets

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.

Unix Sockets

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.

  • If you require interprocess communication in Python multiprocessing.Queue is a much better and easier way!

Socket (ab)use

  • 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...

New toy

  • 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

New(er) toy!

The iRacer from sparkfun.

iRacer features

  • 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.
  • https://www.sparkfun.com/products/11162

Bluetooth

  • One mention of "bluetooth" on the Python 3.3 socket docs...
  • I mean how hard could it be...?
  • To be fair I had to use the source

Bluetooth controlled Car

~~~~{.python} 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]))

~

CAN

  • The Controller Area Network is a bus standard designed to allow microcontrollers and devices to communicate with each other.
  • It has priority based bus arbitration, reliable deterministic communication.
  • Used in cars, trucks, wheelchairs... learn more at http://en.wikipedia.org/wiki/CAN_bus.

SocketCAN is a set of open source CAN drivers and a networking stack contributed by Volkswagen Research to the Linux kernel.

Virtual Can

On reasonably modern GNU/Linux systems open a virtual can interface:

sudo modprobe vcan
sudo ip link add dev vcan0 type vcan
sudo ifconfig vcan0 up

Socket Can

With the hardware and appropriate socketcan kernel module, open a real CAN device:

sudo ip link set can0 up type can bitrate 1000000
  • Allows very easy filtering in the kernel (fast)

Python and SocketCan

# create a raw socket
s = socket.socket(socket.AF_CAN, socket.SOCK_RAW, socket.CAN_RAW)

# We can only filter on just the bits of the can_id in this mask:
can_mask = 0x00F0
# Create the filter
rfilter = struct.pack(can_filter_fmt, can_id, can_mask)

# Pass those filter options to the kernel via socket.setsockopt
s.setsockopt(socket.SOL_CAN_RAW, socket.CAN_RAW_FILTER, rfilter)

#bind our CAN socket to the 'can0' network interface
s.bind(('can0',))

eLua

  • full implementation of the Lua Programming Language for the embedded world
  • eLua runs on the "bare-metal"
  • awesome for prototype and experiments on a Rapid Application Develop model

LM3S Eval Board

  • Has CAN
  • And a simple serial interface

To start my eLua dev board spamming CAN messages: miniterm.py --port=/dev/ttyUSB0 --baud=115200

lua /mmc/bcan.lua

Then on the PC run wireshark or my real_raw_can.py demo.

Sockets for Broadcast-Manager (BCM)

  • The Broadcast-Manager provides functions to send messages on the CAN bus once or periodically, as well as notify of changes in received CAN frames, recognizing specific CAN IDs.
  • I.E. Black Magic
  • Least documented thing I've ever seen - http://www.brownhat.org/docs/socketcan/llcf-api.html