TCP/IP, sockets og klient-server-arkitektur.
Når programmer kommuniserer over nettverk – enten lokalt eller over internett – bruker de protokoller for å sikre at data sendes og mottas korrekt. Den grunnleggende modellen for nettverkskommunikasjon er klient-server-arkitekturen.
I dette kapittelet skal vi se på:
- TCP/IP-modellen
- Klient-server-arkitektur
- Sockets (nettverkskommunikasjon på lavt nivå)
- HTTP-protokollen i praksis
- Portnumre og IP-adresser
- Klienten sender forespørsler (eksempel: nettleser, app)
- Serveren mottar forespørsler og sender svar (eksempel: webserver, API-server)
Eksempler:
- Du (klient) ber om en nettside → Webserveren (server) sender HTML
- Spotify-appen (klient) ber om en sang → Spotify-serveren (server) streamer musikk
- Python-program (klient) spør API → API-server (server) sender JSON-data
Serveren er alltid i gang og venter på forespørsler, mens klienten starter kommunikasjonen.
Internett bygger på TCP/IP-protokollstakken, som har fire lag:
4. Applikasjonslaget:
- HTTP, HTTPS, FTP, SMTP, DNS
- Det programmet ditt jobber med direkte
3. Transportlaget:
- TCP (Transmission Control Protocol): Pålitelig, ordnet levering
- UDP (User Datagram Protocol): Raskere, men upålitelig
- Håndterer portnumre (port 80 = HTTP, port 443 = HTTPS)
2. Internetlaget:
- IP (Internet Protocol): Adressering og ruting
- IP-adresser (IPv4: 192.168.1.1, IPv6)
1. Linklaget:
- Fysisk overføring (Ethernet, Wi-Fi)
- Ikke noe du programmerer direkte
Når du sender data:
1. Applikasjonslaget pakker data (f.eks. HTTP-forespørsel)
2. TCP deler opp i segmenter og legger til portnummer
3. IP legger til IP-adresser
4. Data sendes fysisk over nettverket
✅ Pålitelig – garanterer at data kommer frem
✅ Ordnet – data kommer i riktig rekkefølge
✅ Feilsjekking – oppdager og retter feil
❌ Tregere – mye overhead
Bruksområder: HTTP, e-post, filoverføring
UDP (User Datagram Protocol):
✅ Raskere – mindre overhead
✅ Enklere – ingen forbindelsesoppsett
❌ Upålitelig – data kan gå tapt
❌ Ingen rekkefølge-garanti
Bruksområder: Videostreaming, gaming, DNS
Tommelfingerregel: Bruk TCP når data må være korrekt, UDP når hastighet er viktigere.
- IPv4:
192.168.1.10 (4 deler, 0-255)- IPv6:
2001:0db8:85a3::8a2e:0370:7334 (lengre, flere adresser)-
127.0.0.1 eller localhost = din egen maskinPortnummer: Identifiserer en tjeneste/applikasjon på enheten
- 0-65535 (totalt 65536 porter)
- 0-1023: Velkjente porter (well-known ports)
- 80: HTTP
- 443: HTTPS
- 22: SSH
- 21: FTP
- 1024-49151: Registrerte porter
- 49152-65535: Dynamiske/private porter
Adresse-format:
IP:PORT
192.168.1.10:8080
localhost:5000
example.com:80En server kan ha mange tjenester på samme IP, men ulike porter.
En socket er et endepunkt for nettverkskommunikasjon. Det er grensesnittet mellom applikasjonen din og nettverket.
Typer:
- Stream socket (TCP): Pålitelig, toveis datastrøm
- Datagram socket (UDP): Upålitelig, meldingsbasert
En socket identifiseres av:
- IP-adresse
- Portnummer
- Protokoll (TCP/UDP)
Python har en innebygd socket-modul for lavnivå nettverksprogrammering.
La oss lage en enkel TCP-server som lytter på en port:
import socket
# Opprett socket
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# Bind til adresse og port
host = 'localhost'
port = 9999
server_socket.bind((host, port))
# Lytt etter tilkoblinger (maks 5 i kø)
server_socket.listen(5)
print(f"Server lytter på {host}:{port}")
while True:
# Aksepter tilkobling
client_socket, address = server_socket.accept()
print(f"Tilkobling fra {address}")
# Motta data
data = client_socket.recv(1024).decode('utf-8')
print(f"Mottatt: {data}")
# Send svar
melding = f"Echo: {data}"
client_socket.send(melding.encode('utf-8'))
# Lukk tilkobling
client_socket.close()Forklaring:
- AF_INET = IPv4
- SOCK_STREAM = TCP
- bind() binder socket til IP og port
- listen() gjør serveren klar til å motta tilkoblinger
- accept() venter på klient (blokkerer)
- recv(1024) mottar opptil 1024 bytes
Her er en klient som kobler til serveren:
import socket
# Opprett socket
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# Koble til server
host = 'localhost'
port = 9999
client_socket.connect((host, port))
print(f"Koblet til {host}:{port}")
# Send data
melding = "Hei fra klienten!"
client_socket.send(melding.encode('utf-8'))
# Motta svar
svar = client_socket.recv(1024).decode('utf-8')
print(f"Svar fra server: {svar}")
# Lukk forbindelse
client_socket.close()Kjøring:
1. Start serveren først (kjør server.py)
2. Start klienten (kjør client.py)
Output (server):
Server lytter på localhost:9999
Tilkobling fra ('127.0.0.1', 54321)
Mottatt: Hei fra klienten!Output (klient):
Koblet til localhost:9999
Svar fra server: Echo: Hei fra klienten!HTTP-forespørsel består av:
1. Startlinje: Metode, URL, HTTP-versjon
2. Headers: Metadata (Content-Type, User-Agent, osv.)
3. Tom linje
4. Body: Data (for POST/PUT)
Eksempel:
GET /api/users HTTP/1.1
Host: example.com
User-Agent: Mozilla/5.0
Accept: application/json
HTTP-respons består av:
1. Statuslinje: HTTP-versjon, statuskode, statusmelding
2. Headers: Metadata
3. Tom linje
4. Body: Innhold (HTML, JSON, osv.)
Eksempel:
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 53
{"id": 1, "navn": "Emma", "alder": 18}La oss sende en rå HTTP-forespørsel med sockets:
import socket
def http_request(host, path='/'):
"""Send HTTP GET-forespørsel med socket"""
# Opprett socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# Koble til server (port 80 for HTTP)
s.connect((host, 80))
# Lag HTTP-forespørsel
request = f"GET {path} HTTP/1.1\r\n"
request += f"Host: {host}\r\n"
request += "Connection: close\r\n"
request += "\r\n"
# Send forespørsel
s.send(request.encode('utf-8'))
# Motta svar
response = b''
while True:
chunk = s.recv(4096)
if not chunk:
break
response += chunk
# Lukk socket
s.close()
# Dekod og returner
return response.decode('utf-8', errors='ignore')
# Test
response = http_request('example.com', '/')
print(response[:500]) # Første 500 tegnOutput:
HTTP/1.1 200 OK
Content-Type: text/html; charset=UTF-8
Content-Length: 1256
...
<!doctype html>
<html>
<head>
<title>Example Domain</title>
...Dette viser hvordan HTTP egentlig fungerer under panseret – det er bare tekstmeldinger sendt over TCP!
Som du ser av forrige eksempel, er det mye arbeid å håndtere HTTP med rå sockets. Derfor bruker vi requests-biblioteket:
Med sockets (lavnivå):
- Må lage HTTP-forespørsel manuelt
- Må parse HTTP-svar manuelt
- Må håndtere encoding/decoding
- Må håndtere HTTPS separat (SSL/TLS)
- Mye kode for enkle oppgaver
Med requests (høynivå):
- Enkel API: requests.get(url)
- Automatisk parsing av JSON
- Automatisk håndtering av HTTPS
- Innebygd støtte for cookies, sessions, osv.
- Få linjer kode
Når bruke hva?
- requests: Når du jobber med HTTP/API-er (99% av tilfellene)
- sockets: Når du lager egne protokoller eller trenger full kontroll
For webutvikling og API-bruk: Alltid bruk requests.
La oss lage en enkel chat-server som kan håndtere flere klienter:
import socket
import threading
klienter = []
def haandter_klient(client_socket, address):
"""Håndter en klient i egen tråd"""
print(f"{address} koblet til")
while True:
try:
# Motta melding
melding = client_socket.recv(1024).decode('utf-8')
if not melding:
break
print(f"{address}: {melding}")
# Send til alle andre klienter
for klient in klienter:
if klient != client_socket:
klient.send(f"{address}: {melding}".encode('utf-8'))
except:
break
# Fjern klient og lukk
klienter.remove(client_socket)
client_socket.close()
print(f"{address} koblet fra")
def start_server():
"""Start chat-server"""
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind(('localhost', 9999))
server.listen(5)
print("Chat-server startet på localhost:9999")
while True:
client_socket, address = server.accept()
klienter.append(client_socket)
# Start ny tråd for hver klient
thread = threading.Thread(target=haandter_klient, args=(client_socket, address))
thread.start()
start_server()Chat-klient:
import socket
import threading
def motta_meldinger(s):
"""Motta meldinger i egen tråd"""
while True:
try:
melding = s.recv(1024).decode('utf-8')
if melding:
print(f"\n{melding}")
except:
break
# Koble til server
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('localhost', 9999))
# Start tråd for å motta meldinger
thread = threading.Thread(target=motta_meldinger, args=(s,))
thread.start()
# Send meldinger
while True:
melding = input()
s.send(melding.encode('utf-8'))Dette viser praktisk bruk av sockets for sanntidskommunikasjon.
Oppsummering
I dette kapittelet har du lært:
- Klient-server-modellen: klient ber, server svarer.
- TCP vs. UDP: pålitelig og ordnet mot rask og forbindelsesloes.
- Sockets: endepunkt for nettverkskommunikasjon.
- TCP-server og -klient: enkel nettverkskommunikasjon i Python.
- Chat-server: praktisk eksempel på nettverksprogrammering.
Noekkelbegreper
| Begrep | Forklaring |
|---|---|
| Klient-server | Klienten ber, serveren svarer |
| TCP | Pålitelig, ordnet dataoverfoering |
| Socket | Endepunkt for nettverkskommunikasjon |
Oppgaver
Dette kapitlet er skrevet av Anthropics toppmodeller (Claude Opus og Claude Fable) og er foreløpig ikke manuelt gjennomgått — kvalitetskontrollen gjøres av uavhengige KI-agenter, og innmeldte feil rettes fortløpende. Funnet en feil? Meld fra, så retter vi den. Les mer om hvordan innholdet lages.