Semua library HTTP yang akan kita pakai pada chapter berikutnya — urllib, requests, httpx — pada akhirnya berdiri di atas satu module standard library bernama socket. Dengan menulis komunikasi jaringan langsung di atas socket, kita melihat bentuk paling mentah dari koneksi TCP: bind, listen, accept, connect, send, dan recv. Pada Chapter ini kita akan membangun program echo server dan klien sungguhan yang saling bertukar pesan di localhost.
Socket, Titik Ujung Komunikasi #
Socket adalah titik ujung (endpoint) sebuah koneksi jaringan. Untuk membuat socket, kita menyebutkan dua informasi: address family (socket.AF_INET untuk IPv4) dan type (socket.SOCK_STREAM untuk TCP atau socket.SOCK_DGRAM untuk UDP). Server membuat socket lalu mengikatnya ke alamat dan port, sedangkan klien membuat socket lalu menyambungkannya ke alamat server.
String dan Bytes, Dua Dunia yang Wajib Diterjemahkan #
Aturan paling penting sebelum menulis kode socket: jaringan hanya mengirim dan menerima bytes, bukan str. Karena itu setiap pesan harus di-encode sebelum dikirim dan di-decode setelah diterima:
pesan = "Selamat pagi, Budi!"
data = pesan.encode("utf-8")
print(data)
print(type(data))
pesan_balik = data.decode("utf-8")
print(pesan_balik)Output yang Dihasilkan:
b'Selamat pagi, Budi!'
<class 'bytes'>
Selamat pagi, Budi!Mari kita telaah baris-baris kode di atas:
- Baris 3 (
pesan.encode("utf-8")): Method.encode()mengubah string menjadi objectbytessesuai encoding UTF-8; huruf ASCII menjadi byte yang sama, huruf khusus menjadi dua-tiga byte. - Baris 4-5: Tampilan
b'...'menandakan tipebytes, bukanstr—type()mengonfirmasi hal tersebut. - Baris 7 (
data.decode("utf-8")): Method.decode()menerjemahkan kembali bytes menjadi string, dan keduanya harus memakai encoding yang sama.
Server dan Klien TCP Echo #
Program berikut adalah pasangan server-klien sungguhana. Server menerima pesan apa pun dari klien, lalu mengirimkan kembali pesan yang sama (itulah echo). Simpan sebagai server-echo.py:
import socket
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind(("127.0.0.1", 7000))
server.listen()
print("Server echo berjalan di 127.0.0.1:7000")
while True:
koneksi, alamat = server.accept()
print(f"Klien terhubung dari {alamat[0]}")
with koneksi:
while True:
data = koneksi.recv(1024)
if not data:
break
koneksi.sendall(data)Lalu simpan klien sebagai klien-echo.py:
import socket
with socket.create_connection(("127.0.0.1", 7000), timeout=3) as koneksi:
koneksi.sendall("Halo, server!".encode("utf-8"))
balasan = koneksi.recv(1024)
print("Balasan:", balasan.decode("utf-8"))Jalankan server di satu terminal (python3 server-echo.py), lalu klien di terminal kedua (python3 klien-echo.py).
Output di terminal server:
Server echo berjalan di 127.0.0.1:7000
Klien terhubung dari 127.0.0.1Output di terminal klien:
Balasan: Halo, server!Mari kita bedah kode kedua program tersebut:
- Baris 3-5 server (
socket→bind→listen): Server membuat socket TCP, mengikatnya ke127.0.0.1port7000, lalu mulai mendengarkan. - Baris 9 (
server.accept()): Functionaccept()memblokir eksekusi server sampai ada klien yang tersambung, lalu mengembalikan socket baru khusus untuk koneksi tersebut. - Baris 13 (
koneksi.recv(1024)): Methodrecv()menunggu data masuk; angka1024adalah ukuran maksimal potongan data yang dibaca sekali baca. - Baris 14-15 (
if not data: break): Saat klien menutup koneksi,recv()mengembalikanb''yang bernilai salah, sehingga loop berhenti dan server siap menerima klien berikutnya. - Baris 3 klien (
socket.create_connection(...)): Function praktis yang membuat socket, memanggilconnect()ke alamat tujuan, sekaligus memasangtimeout=3detik; blokwithmemastikan koneksi tertutup otomatis. - Baris 4-5 klien: Pesan
"Halo, server!"di-encode menjadi bytes olehsendall(), lalu balasan darirecv()di-decode kembali menjadi string untuk dicetak.
Sedikit Rasa UDP #
UDP tidak memakai koneksi sama sekali — data dikirim sebagai datagram dengan alamat tujuan menempel pada setiap paket. Simpan sebagai server-udp.py:
import socket
server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
server.bind(("127.0.0.1", 7001))
print("Server UDP berjalan di 127.0.0.1:7001")
while True:
data, alamat = server.recvfrom(1024)
print("Diterima:", data.decode("utf-8"))
server.sendto(data.upper(), alamat)Dan klien klien-udp.py:
import socket
klien = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
klien.settimeout(3)
klien.sendto("belajar jaringan".encode("utf-8"), ("127.0.0.1", 7001))
balasan, _ = klien.recvfrom(1024)
print("Balasan:", balasan.decode("utf-8"))Output di terminal klien:
Balasan: BELAJAR JARINGANPerhatikan dua perbedaan utamanya: server tidak memanggil listen() dan accept(), serta method recvfrom() mengembalikan pasangan (data, alamat) karena setiap datagram datang tanpa koneksi — server harus tahu alamat pengirim agar tahu ke mana membalas melalui sendto(). Dengan bekal socket ini, kita siap naik ke protokol yang memakainya paling banyak: HTTP.