Setiap server jaringan berdiri di atas rangkaian panggilan sistem yang sama, dan chat server kita tidak terkecuali. Sebelum ada thread, protokol, atau broadcast, kita terlebih dahulu memastikan server mampu berdiri: membuat socket TCP, mengikatnya ke antarmuka loopback, memasang antrean koneksi dengan listen, dan menerima client satu per satu lewat accept. Empat panggilan itulah kerangka yang kita bangun di bagian pertama. Kita juga memilih satu keputusan praktis yang berulang di seluruh proyek: port dibiarkan dipilih sistem operasi lewat bind ke port 0, lalu dibaca kembali dengan getsockname — cara yang sama dengan chapter TCP Socket dengan POSIX Socket API, sehingga skenario uji tidak pernah bertabrakan dengan port milik proses lain.
Empat Panggilan yang Menjadi Fondasi #
Potongan berikut adalah tahap kerangka chat-server.cpp. Kode ini belum lengkap — bagian yang menghidupkan server menyusul di bagian 2 — tetapi alur socket sampai accept sudah final dan tidak berubah lagi:
#include <arpa/inet.h> // htons, htonl
#include <netinet/in.h> // struct sockaddr_in, INADDR_LOOPBACK
#include <sys/socket.h> // socket, bind, listen, accept
#include <unistd.h> // close
int main() {
// 1) Socket pendengar: socket -> bind -> listen di loopback, port 0.
const int fdListen = ::socket(AF_INET, SOCK_STREAM, 0);
sockaddr_in alamat{};
alamat.sin_family = AF_INET;
alamat.sin_port = htons(0); // OS memilih port bebas
alamat.sin_addr.s_addr = htonl(INADDR_LOOPBACK); // 127.0.0.1
if (::bind(fdListen, reinterpret_cast<const sockaddr*>(&alamat),
sizeof(alamat)) < 0 ||
::listen(fdListen, 8) < 0) {
return 1;
}
// Port yang benar dibaca lewat getsockname, lalu diberi ke client.
sockaddr_in terikat{};
socklen_t panjangTerikat = sizeof(terikat);
::getsockname(fdListen, reinterpret_cast<sockaddr*>(&terikat),
&panjangTerikat);
const uint16_t port = terikat.sin_port; // sudah network byte order
}Mari kita telaah apa yang terjadi pada baris-baris penting di atas:
socket(AF_INET, SOCK_STREAM, 0): membuat file descriptor TCP —AF_INETmemilih alamat IPv4 danSOCK_STREAMmemilih layanan berbasis aliran byte yang andal, ciri khas TCP.alamat.sin_port = htons(0): port 0 adalah permintaan eksplisit agar kernel memilih port bebas;htonsmengubah nilai ke network byte order yang diwajibkan protokol jaringan.INADDR_LOOPBACK: server hanya mendengarkan di 127.0.0.1, sehingga skenario uji tidak pernah terekspos ke luar mesin — keputusan penting untuk program yang dikompilasi dan dijalankan otomatis.bindlalulisten:bindmenempelkan alamat ke socket,listen(fdListen, 8)mengaktifkan antrean koneksi dengan kedalaman 8; keduanya digabung dalam satu pemeriksaan galat karena kegagalan salah satu sama-sama bermakna “server tidak bisa berdiri”.getsockname: membaca alamat yang benar-benar terikat — tanpa panggilan ini kita tidak tahu port mana yang dipilih kernel untuk port 0.
Struktur Koneksi dan Keputusan Desain #
Kerangka ini menetapkan tiga keputusan yang membawa kita lewat seluruh proyek. Pertama, server mengikat dirinya ke loopback saja; chat nyata di dunia luar cukup mengganti satu konstanta menjadi INADDR_ANY, tetapi untuk belajar dan menguji, loopback lebih aman. Kedua, port ephemeral membuat proyek bisa dijalankan berulang tanpa galat “address already in use”. Ketiga, angka 8 pada listen adalah backlog — panjang antrean koneksi yang belum di-accept; untuk dua client skenario kita angka ini jauh lebih dari cukup, tetapi angka tersebut tetap kita tulis eksplisit agar keertiannya terbaca.
Kerangka sudah berdiri, tetapi belum hidup: belum ada yang menerima koneksi, belum ada client, dan belum ada pesan yang mengalir. Bagian 2 menambahkan lapisan itu — thread penerima per client, daftar koneksi bersama, dan broadcast pesan yang tersinkronisasi.