pm21-dragon/lectures/lecture-11/network and web technologies.ipynb
2025-01-10 11:26:08 +01:00

23 KiB
Raw Blame History

None <html> <head> </head>

Network and web technologies

(I.e. how can we interact with services on other computers from Python?)

Teletype machines "were adapted to provide a user interface to early mainframe computers and minicomputers, sending typed data to the computer and printing the response."

WACsOperateTeletype.jpg WWII era teletype machines. Source: https://commons.wikimedia.org/wiki/File:WACsOperateTeletype.jpg

Let's start with an idealized "serial port"

serial-port.png

Data is carried as a serial stream of bits (1s and 0s, high and low voltage).

We can think about teletype machines, USB, ethernet cables, WiFi/WLAN, and so on:

(From https://www.electroschematics.com/wp-content/uploads/2010/01/usb-wiring-connection.jpg?fit=1024%2C768) usb-wiring-connection.jpg

receiver-wiring-to-FC.png Source: https://www.expresslrs.org/quick-start/receivers/wiring-up/

(Ethernet cables get more sophisticated. https://serverfault.com/questions/449416/why-do-ethernet-cables-have-8-wires . This is a theme that repeats itself in computer networking.)

But this is not a "network", only two computers

From serial to network

We can build a robust network composed of many individual serial links by defining a common language -- namely packets with framing information - such as a destination address - and a payload. The individual nodes in the network use the framing information to forward the packet or to consume it.

This standardization has allowed hardware and software producers to interoperate by having common interfaces. Here is an ethernet frame:

Ethernet_Type_II_Frame_format.svg.png Source: https://commons.wikimedia.org/wiki/File:Ethernet_Type_II_Frame_format.svg

USB also uses the idea of frames to establish a standard for a robust single link "network". Here is a USB frame:

640px-USB_signal_example.svg.png "Data packets would have address field and payload between the packet ID and the end of packet." Source: https://commons.wikimedia.org/wiki/File:USB_signal_example.svg

640px-Speedport_W_921V,_Deutsche_Telekom-7294.jpg Source: https://de.m.wikipedia.org/wiki/Datei:Speedport_W_921V,_Deutsche_Telekom-7294.jpg

640px-Speedport_W_921V,_Deutsche_Telekom-7296.jpg Source: https://commons.wikimedia.org/wiki/File:Speedport_W_921V,_Deutsche_Telekom-7296.jpg

Wireless-router-network-diagram.png Source: https://www.conceptdraw.com/How-To-Guide/what-is-a-wireless-network

DHCP - Dynamic Host Configuration Protocol

DHCP is the protocol used when your computer first joins a network and asks for an IP address.

DHCP-protocol.png Source: https://www.boardinfinity.com/blog/dynamic-host-configuration-protocol-dhcp/

These notes give an overview of the most important of these levels with the idea of understanding what your computer is doing when you use the web browser or how a program you write would interact automatically with, for example, a remote server to perform a BLAST query.

TCP and UDP

From https://microchipdeveloper.com/tcpip:tcp-vs-udp tcp-vs-udp.jpg

In addition to source and destination address, TCP and UDP frames have "port" and thus address has a 2^16 (65536) TCP ports and 2^16 UDP ports.

In [15]:
!curl http://google.com/bananas
<!DOCTYPE html>
<html lang=en>
  <meta charset=utf-8>
  <meta name=viewport content="initial-scale=1, minimum-scale=1, width=device-width">
  <title>Error 404 (Not Found)!!1</title>
  <style>
    *{margin:0;padding:0}html,code{font:15px/22px arial,sans-serif}html{background:#fff;color:#222;padding:15px}body{margin:7% auto 0;max-width:390px;min-height:180px;padding:30px 0 15px}* > body{background:url(//www.google.com/images/errors/robot.png) 100% 5px no-repeat;padding-right:205px}p{margin:11px 0 22px;overflow:hidden}ins{color:#777;text-decoration:none}a img{border:0}@media screen and (max-width:772px){body{background:none;margin-top:0;max-width:none;padding-right:0}}#logo{background:url(//www.google.com/images/branding/googlelogo/1x/googlelogo_color_150x54dp.png) no-repeat;margin-left:-5px}@media only screen and (min-resolution:192dpi){#logo{background:url(//www.google.com/images/branding/googlelogo/2x/googlelogo_color_150x54dp.png) no-repeat 0% 0%/100% 100%;-moz-border-image:url(//www.google.com/images/branding/googlelogo/2x/googlelogo_color_150x54dp.png) 0}}@media only screen and (-webkit-min-device-pixel-ratio:2){#logo{background:url(//www.google.com/images/branding/googlelogo/2x/googlelogo_color_150x54dp.png) no-repeat;-webkit-background-size:100% 100%}}#logo{display:inline-block;height:54px;width:150px}
  </style>
  <a href=//www.google.com/><span id=logo aria-label=Google></span></a>
  <p><b>404.</b> <ins>Thats an error.</ins>
  <p>The requested URL <code>/bananas</code> was not found on this server.  <ins>Thats all we know.</ins>

Let's practice with the Star Wars API.

curl https://swapi.py4e.com/api/people/1/

We will use the requests library.

In [6]:
import requests
In [19]:
response = requests.get('https://swapi.py4e.com/api/people/5/')
response.text
Out[19]:
'{"name":"Leia Organa","height":"150","mass":"49","hair_color":"brown","skin_color":"light","eye_color":"brown","birth_year":"19BBY","gender":"female","homeworld":"https://swapi.py4e.com/api/planets/2/","films":["https://swapi.py4e.com/api/films/1/","https://swapi.py4e.com/api/films/2/","https://swapi.py4e.com/api/films/3/","https://swapi.py4e.com/api/films/6/","https://swapi.py4e.com/api/films/7/"],"species":["https://swapi.py4e.com/api/species/1/"],"vehicles":["https://swapi.py4e.com/api/vehicles/30/"],"starships":[],"created":"2014-12-10T15:20:09.791000Z","edited":"2014-12-20T21:17:50.315000Z","url":"https://swapi.py4e.com/api/people/5/"}'
In [20]:
type(response)
Out[20]:
requests.models.Response
In [21]:
type(response.text)
Out[21]:
str
In [22]:
response.headers
Out[22]:
{'Date': 'Fri, 10 Jan 2025 10:02:19 GMT', 'Content-Type': 'application/json', 'Transfer-Encoding': 'chunked', 'Connection': 'keep-alive', 'Vary': 'Accept-Encoding, Accept, Cookie', 'X-Frame-Options': 'SAMEORIGIN', 'ETag': 'W/"568eba5ec38fb919307c6156c938e302"', 'Allow': 'GET, HEAD, OPTIONS', 'X-Clacks-Overhead': 'GNU Terry Pratchett', 'Content-Encoding': 'gzip', 'Cache-Control': 'max-age=14400', 'CF-Cache-Status': 'MISS', 'Report-To': '{"endpoints":[{"url":"https:\\/\\/a.nel.cloudflare.com\\/report\\/v4?s=9AOD88Z9mF%2BfE49ehipfEzpbXz5xs%2B4GabJ8Ds0jAtf4Tdbvyb7hw1bRuVxxgFRriVgTcIoux8CnjfAtBrwXqZGjUsaAZ8ZeOtRZCkSSqU%2BS2gLP%2FGw2qGsrRuLXIL7hproJjLdxEITm48COOw%3D%3D"}],"group":"cf-nel","max_age":604800}', 'NEL': '{"success_fraction":0,"report_to":"cf-nel","max_age":604800}', 'Server': 'cloudflare', 'CF-RAY': '8ffbd4ae6d082c0e-STR', 'alt-svc': 'h3=":443"; ma=86400', 'server-timing': 'cfL4;desc="?proto=TCP&rtt=14991&min_rtt=9209&rtt_var=7584&sent=5&recv=6&lost=0&retrans=0&sent_bytes=2828&recv_bytes=781&delivery_rate=439135&cwnd=252&unsent_bytes=0&cid=b7a8064f0ebc6e2d&ts=256&x=0"'}
In [23]:
x = response.json()
x
Out[23]:
{'name': 'Leia Organa',
 'height': '150',
 'mass': '49',
 'hair_color': 'brown',
 'skin_color': 'light',
 'eye_color': 'brown',
 'birth_year': '19BBY',
 'gender': 'female',
 'homeworld': 'https://swapi.py4e.com/api/planets/2/',
 'films': ['https://swapi.py4e.com/api/films/1/',
  'https://swapi.py4e.com/api/films/2/',
  'https://swapi.py4e.com/api/films/3/',
  'https://swapi.py4e.com/api/films/6/',
  'https://swapi.py4e.com/api/films/7/'],
 'species': ['https://swapi.py4e.com/api/species/1/'],
 'vehicles': ['https://swapi.py4e.com/api/vehicles/30/'],
 'starships': [],
 'created': '2014-12-10T15:20:09.791000Z',
 'edited': '2014-12-20T21:17:50.315000Z',
 'url': 'https://swapi.py4e.com/api/people/5/'}
In [24]:
x = response.json()
print(type(x))
x['name']
<class 'dict'>
Out[24]:
'Leia Organa'
In [30]:
requests.get('https://swapi.py4e.com/api/people/6/').json()['name']
Out[30]:
'Owen Lars'
In [32]:
# webserver1.py from https://ruslanspivak.com/lsbaws-part1/

import socket
HOST, PORT = '0.0.0.0', 4449

listen_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
listen_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
listen_socket.bind((HOST, PORT))
listen_socket.listen(1)
print(f'Serving HTTP on port {PORT} ...')
while True:
    print("waiting for connection")
    client_connection, client_address = listen_socket.accept()
    print("Got connection from {}".format(client_address))
    request_data = client_connection.recv(1024)
    print(request_data.decode('utf-8'))

    http_response = b"""\
HTTP/1.1 200 OK

Hello, World! Guten tag.
"""
    client_connection.sendall(http_response)
    client_connection.close()
Serving HTTP on port 4449 ...
waiting for connection
Got connection from ('127.0.0.1', 64530)
HTTP/1.1 GET /hello

waiting for connection
Got connection from ('127.0.0.1', 64555)
l;askdjkfsd;kljfd;lskjfkldsjfklajlkdsfmvmdnsvmngfkljsrjhkfasfasdasdfsafasfasd

waiting for connection
---------------------------------------------------------------------------
KeyboardInterrupt                         Traceback (most recent call last)
Cell In[32], line 13
     11 while True:
     12     print("waiting for connection")
---> 13     client_connection, client_address = listen_socket.accept()
     14     print("Got connection from {}".format(client_address))
     15     request_data = client_connection.recv(1024)

File ~/anaconda3/envs/wm01-dragon/lib/python3.11/socket.py:294, in socket.accept(self)
    287 def accept(self):
    288     """accept() -> (socket object, address info)
    289 
    290     Wait for an incoming connection.  Return a new socket
    291     representing the connection, and the address of the client.
    292     For IP sockets, the address info is a pair (hostaddr, port).
    293     """
--> 294     fd, addr = self._accept()
    295     sock = socket(self.family, self.type, self.proto, fileno=fd)
    296     # Issue #7995: if no default timeout is set and the listening
    297     # socket had a (non-zero) timeout, force the new socket in blocking
    298     # mode to override platform-specific socket flags inheritance.

KeyboardInterrupt: 

With telnet:

telnet 127.0.0.1 4448
GET / HTTP/1.1
Host: blahblah.com

HTML, CSS, and Javascript and WASM - browser languages

https://developer.mozilla.org/en-US/docs/Web

E.g. https://codepen.io/picks/pens/

JSON

In [33]:
import json

data1 = {'key1':[1.2,{32: 64,"c":"sdfg'dfsg"},3,4]}

print(type(data1))
buf = json.dumps(data1)
print(type(buf))
# buf

data2 = json.loads(buf)
print(type(data2))
data2
<class 'dict'>
<class 'str'>
<class 'dict'>
Out[33]:
{'key1': [1.2, {'32': 64, 'c': "sdfg'dfsg"}, 3, 4]}
In [34]:
buf
Out[34]:
'{"key1": [1.2, {"32": 64, "c": "sdfg\'dfsg"}, 3, 4]}'
</html>