Chapter ss dan netstat
menutup dengan janji dua alat klasik, dan inilah keduanya. curl dan wget adalah klien yang paling sering kita ketik begitu pindah kursi dari pihak yang mendengarkan ke pihak yang menyambung: yang pertama serba bisa mengirim dan menerima data lewat hampir semua protokol berbasis URL, yang kedua spesialis mengunduh berkas sampai tuntas. Keduanya tampak serupa di permukaan, tetapi dirancang untuk kebiasaan yang berbeda — curl untuk percakapan singkat request-response, wget untuk pengambilan berkas yang panjang dan sabar. Kita akan membedah keduanya dengan server lokal di loopback seperti biasa, lalu menutup dengan pemanggilan API JSON — pola yang sama dengan yang dipakai skrip otomatisasi setiap hari.
Dua Alat dengan Dua Kebiasaan #
Perbedaan paling dalam antara keduanya ada pada pertanyaan yang mereka jawab. curl menjawab “apa yang dikatakan server bila saya kirim permintaan ini?” — karenanya keluaran bawaannya adalah stdout, tempat hasil di-pipe ke perintah lain. wget menjawab “bagaimana mengambil berkas itu sampai tuntas?” — karenanya keluaran bawaannya adalah berkas di disk, lengkap dengan progress bar dan kemampuan melanjutkan unduhan yang terputus. Perbandingan singkatnya:
| Aspek | curl | wget |
|---|---|---|
| Fokus utama | transfer data dua arah (request/response) | unduhan berkas |
| Protokol | HTTP(S), FTP, SFTP, SMTP, dan lainnya | HTTP(S), FTP |
| Keluaran bawaan | mencetak ke stdout | menyimpan ke berkas |
| Melanjutkan unduhan putus | -C - | -c |
| Unduhan rekursif | tidak didukung | -r, --mirror |
Mengunduh Berkas dengan curl #
Empat opsi curl menutup hampir semua kebutuhan harian. Opsi -s (silent) meredam progress bar agar keluaran bersih untuk di-pipe; -o nama.txt menyimpan balasan ke berkas bernama nama.txt; -O (huruf besar) menyimpan memakai nama berkas dari URL itu sendiri; dan -L mengikuti redirect HTTP — penting karena banyak URL modern hanya menjawab “pindah ke sana”. Kita uji rangkaian itu terhadap server mini di loopback, lalu memastikan berkas hasil unduhan identik dengan aslinya lewat diff:
printf 'isi berkas penting\n' > berkas.txt
python3 -m http.server 8765 --bind 127.0.0.1 >/dev/null 2>&1 &
server=$!
for i in 1 2 3 4 5; do curl -s -o /dev/null 127.0.0.1:8765/ && break; sleep 0.2; done
curl -s 127.0.0.1:8765/berkas.txt
curl -s -o salinan.txt 127.0.0.1:8765/berkas.txt
diff berkas.txt salinan.txt && echo "berkas identik"
kill "$server"Output yang Dihasilkan:
isi berkas penting
berkas identikMari kita bedah baris demi baris:
- Baris 1 (
printf 'isi berkas penting\n' > berkas.txt): menyiapkan berkas asal yang isinya pasti — nanti dibandingkan dengan hasil unduhan. - Baris 2-3: server HTTP Python dinyalakan di background pada
127.0.0.1:8765, PID-nya disimpan ke variabelserveragar bisa dimatikan dengan bersih. - Baris 4 (
for i in ...): menunggu server siap —curldicoba berulang sampai koneksi diterima, lalubreak. - Baris 5 (
curl -s 127.0.0.1:8765/berkas.txt): mengambil berkas dan mencetak isinya ke stdout — perilaku bawaancurltanpa-o. - Baris 6 (
curl -s -o salinan.txt ...): mengambil berkas yang sama, kali ini disimpan kesalinan.txt. - Baris 7 (
diff ... && echo ...):diffmembandingkan dua berkas; bila identik ia diam, laluechomenyatakan keberhasilan. - Baris 8 (
kill "$server"): mematikan server — kebiasaan penutup yang selalu kita ulang.
Membaca Kode Keluar curl #
curl melaporkan kegagalan lewat kode keluar (exit code), dan opsi -s meredam pesan kesalahan — bukan kegagalannya. Karena itu skrip yang memakai curl selalu memeriksa $?. Kode-kode yang paling sering membedah arah masalah:
| Kode | Arti | Pertanyaan yang terjawab |
|---|---|---|
| 6 | nama host tidak dapat diterjemahkan | DNS bermasalah? |
| 7 | koneksi gagal atau ditolak | host atau port tidak menjawab? |
| 22 | HTTP error (4xx/5xx) dengan opsi -f | server hidup tapi menolak? |
| 28 | tenggat waktu habis | jalur macet atau firewall membuang paket? |
Tanpa -f, curl menganggap sukses setiap balasan HTTP — termasuk 404 — karena dari sisi transfer, datanya memang terkirim; -f membuat kode 404 dan kawan-kawannya diterjemahkan menjadi kegagalan kode 22. Berikut gejala koneksi ke port yang tidak didengarkan siapa pun, persis pemeriksaan penutup Chapter Network Diagnostics
:
curl -sS --max-time 2 127.0.0.1:9999/ 2>&1Output yang Dihasilkan:
curl: (7) Failed to connect to 127.0.0.1 port 9999 after 0 ms: Could not connect to serverOpsi -sS meredam progress bar (-s) tetapi tetap menampilkan pesan kesalahan (-S), dan 2>&1 mengarahkan pesan itu ke stdout — kombinasi favorit di dalam skrip. Pesan Failed to connect dengan kode 7 berarti paket sampai ke mesin tetapi ditolak: tidak ada yang mendengarkan di port tersebut. Bila gejalanya justru menunggu lama lalu gagal kode 28, paket dibuang diam-diam di jalur — biasanya firewall; perbedaan dua gejala ini kita pakai lagi di Chapter Troubleshooting Network
.
wget, Spesialis Unduhan #
wget mengambil satu URL dan menyimpannya sebagai berkas dengan nama yang sama — tanpa opsi apa pun. Di atas kebiasaan dasar itu, opsi yang sering dipakai: -c melanjutkan unduhan yang terputus dari byte terakhir, --limit-rate 500k membatasi kecepatan agar tidak melahap bandwidth kantor, -r mengunduh rekursif mengikuti tautan, dan --mirror menggabungkan rekursif dengan pengecekan stempel waktu untuk mereplikasi situs. Karena progress bar wget menampilkan angka kecepatan yang terus berubah, kita memakai -q agar keluarannya deterministik:
printf 'isi berkas data\n' > data.txt
python3 -m http.server 8765 --bind 127.0.0.1 >/dev/null 2>&1 &
server=$!
for i in 1 2 3 4 5; do curl -s -o /dev/null 127.0.0.1:8765/ && break; sleep 0.2; done
wget -qO hasil.txt 127.0.0.1:8765/data.txt
cat hasil.txt
kill "$server"Output yang Dihasilkan:
isi berkas dataDi sini -O hasil.txt memindahkan tujuan simpan dari data.txt menjadi hasil.txt, lalu cat membuktikan isinya utuh. Perhatikan bahwa blok ini memakai curl untuk menunggu server siap — dua alat ini memang saling melengkapi, bukan saling menggantikan.
Memanggil API dengan curl #
Separuh kegunaan curl yang tidak dimiliki wget ada di sini: mengirim permintaan HTTP dengan metode dan header pilihan kita. Opsi -X POST memilih metode, -H 'Content-Type: application/json' menambahkan header, dan -d '...' mengirim data di badan permintaan — --data @pesanan.json membacanya dari berkas, satu-satunya cara yang nyaman saat datanya panjang. Kita latihan dengan API kecil di loopback yang menerima JSON lalu menjawab JSON; servernya kita tulis dengan Python standar:
printf '{"nama": "Budi", "item": ["kopi", "teh", "susu"]}' > pesanan.json
python3 -c '
import json
from http.server import BaseHTTPRequestHandler, HTTPServer
class Handler(BaseHTTPRequestHandler):
def do_POST(self):
panjang = int(self.headers.get("Content-Length", 0))
data = json.loads(self.rfile.read(panjang))
balasan = {"nama": data["nama"], "jumlah": len(data["item"])}
isi = json.dumps(balasan).encode()
self.send_response(200)
self.send_header("Content-Type", "application/json")
self.send_header("Content-Length", str(len(isi)))
self.end_headers()
self.wfile.write(isi)
def log_message(self, *args):
pass
HTTPServer(("127.0.0.1", 8765), Handler).serve_forever()
' >/dev/null 2>&1 &
server=$!
for i in 1 2 3 4 5; do curl -s -o /dev/null 127.0.0.1:8765/ && break; sleep 0.2; done
curl -s -X POST -H 'Content-Type: application/json' --data @pesanan.json 127.0.0.1:8765/pesanan
printf '\n'
curl -s -X POST -H 'Content-Type: application/json' --data @pesanan.json 127.0.0.1:8765/pesanan | jq -r '.nama + " memesan " + (.jumlah | tostring) + " item"'
kill "$server"Output yang Dihasilkan:
{"nama": "Budi", "jumlah": 3}
Budi memesan 3 itemMari kita bedah bagian-bagian pentingnya:
- Baris 1: berkas
pesanan.jsonberisi data yang akan dikirim sebagai badan permintaan. - Baris 2-24 (server API mini): handler membaca panjang badan dari header
Content-Length, menguraikan JSON masukan, lalu menyusun balasan{"nama": ..., "jumlah": ...}— jumlah dihitung dari panjang arrayitem. - Baris 26-27: server dinyalakan di background dan ditunggu siap dengan pola loop yang sama.
- Baris 28-29: pemanggilan pertama mengirim
pesanan.jsondengan--data @pesanan.jsonlalu mencetak balasan mentahnya;printf '\n'hanya merapikan baris baru. - Baris 30: pemanggilan kedua di-pipe ke
jq -r— filter.namadan.jumlahdigabung menjadi satu kalimat, cara khas memproses jawaban API di dalam skrip.
Dengan curl dan wget di tangan, mesin kita bisa berbicara dengan layanan apa pun di jaringan. Akan tetapi keduanya hanya memindahkan data — login ke mesin jauh, menjalankan perintah di sana, dan menyalin berkas lewat koneksi terenkripsi adalah pekerjaan keluarga OpenSSH: ssh dan scp, Chapter berikutnya.
Referensi lanjut: halaman manual curl(1) untuk daftar lengkap opsi dan kode keluar, wget(1) untuk opsi rekursif dan resume, serta manual jq untuk bahasa filter JSON-nya.