Network Programming · Part 1 — Fundamentals: How Data Actually Travels
The mental model every network programmer needs: the TCP/IP layers, IP addresses & ports, packets, and the client/server model — with a tiny Node.js + TypeScript demo, bilingual, plus exercises.
This is Part 1 of a 10-part series on network programming with Node.js + TypeScript {Đây là Phần 1 của series 10 bài về lập trình mạng với Node.js + TypeScript}. We go from “what is a port” all the way to scaling and debugging real network servers {Ta đi từ “port là gì” đến scale và debug server mạng thật}.
Before we open a single socket, you need one solid mental model: how data actually travels between two programs {Trước khi mở socket đầu tiên, bạn cần một mô hình tư duy vững: dữ liệu thực sự di chuyển thế nào giữa hai chương trình}.
The layered model {Mô hình phân tầng}
Networking is built in layers — each layer only talks to the one above and below it {Mạng được xây theo tầng — mỗi tầng chỉ nói chuyện với tầng trên và dưới nó}. As a programmer you mostly live in the top two, but it helps to see the whole stack {Là lập trình viên, bạn chủ yếu sống ở hai tầng trên cùng, nhưng nhìn cả stack sẽ rất có ích}.
- Application {Ứng dụng}: the protocol your code speaks — HTTP, DNS, WebSocket {giao thức code của bạn nói}.
- Transport {Vận chuyển}: TCP (reliable) or UDP (fast, best-effort), plus ports {TCP tin cậy hoặc UDP nhanh, cùng với port}.
- Internet {Liên mạng}: IP addresses and routing — get a packet from host to host {địa chỉ IP và định tuyến — đưa gói tin từ máy này sang máy khác}.
- Link {Liên kết}: the physical wire / Wi-Fi turning bits into signals {dây vật lý / Wi-Fi biến bit thành tín hiệu}.
Key idea {Ý chính}: you write to a socket at the top; the OS handles every layer below {bạn ghi vào socket ở trên cùng; OS lo mọi tầng bên dưới}.
IP addresses & ports {Địa chỉ IP và port}
An IP address identifies a machine on the network; a port identifies a specific program on that machine {Địa chỉ IP xác định một máy trên mạng; port xác định một chương trình cụ thể trên máy đó}.
Think of it like an apartment building {Hãy tưởng tượng một tòa chung cư}: the IP is the street address, the port is the apartment number {IP là địa chỉ đường, port là số căn hộ}.
93.184.216.34 : 443
└──── IP ────┘ └ port ┘
the machine the program (here: HTTPS)
Some ports are conventions {Một số port là quy ước}: 80 = HTTP, 443 = HTTPS, 53 = DNS, 22 = SSH {…}. Ports 0–1023 are “well-known” and usually need privileges; pick something high (e.g. 3000, 8080) for your own servers {Port 0–1023 là “well-known” và thường cần quyền; chọn số cao cho server của bạn}.
Packets {Gói tin}
Your data is not sent as one big blob {Dữ liệu không được gửi thành một cục lớn}. It is chopped into packets — small chunks that travel independently and may take different routes, arrive out of order, or get lost {Nó bị cắt thành packet — các mảnh nhỏ đi độc lập, có thể đi đường khác nhau, đến sai thứ tự, hoặc thất lạc}.
This single fact explains most of networking {Sự thật này giải thích phần lớn của mạng}:
- TCP reassembles packets into an ordered, reliable stream for you {TCP ráp lại packet thành luồng có thứ tự, tin cậy giúp bạn}.
- UDP just hands you whatever arrives — your problem if it’s missing or reordered {UDP đưa bạn bất cứ thứ gì đến — mất hay sai thứ tự là việc của bạn}.
We will build both in Parts 2 and 3 {Ta sẽ xây cả hai ở Phần 2 và 3}.
The client/server model {Mô hình client/server}
Almost every network app has two roles {Gần như mọi app mạng có hai vai}:
- A server binds to a port and waits for connections {Server gắn vào một port và chờ kết nối}.
- A client initiates a connection to a server’s IP + port {Client khởi tạo kết nối tới IP + port của server}.
That’s it — the rest is what they say to each other {Chỉ vậy thôi — phần còn lại là chúng nói gì với nhau}.
A 12-line taste in Node.js {Nếm thử 12 dòng với Node.js}
You don’t need to understand every line yet — just feel the shape {Bạn chưa cần hiểu từng dòng — chỉ cần cảm nhận hình dạng}. This is a TCP server that greets whoever connects {Đây là server TCP chào bất kỳ ai kết nối}:
import { createServer } from 'node:net';
// A server is just: bind a port, wait, react to each connection.
const server = createServer((socket) => {
console.log('client connected:', socket.remoteAddress);
socket.write('Hello from the server!\n');
socket.end();
});
server.listen(3000, () => {
console.log('listening on port 3000');
});
Run it, then in another terminal connect with a raw client {Chạy nó, rồi ở terminal khác kết nối bằng client thô}:
node server.js # terminal 1
nc localhost 3000 # terminal 2 → prints "Hello from the server!"
nc (netcat) is your best friend for poking at servers {nc (netcat) là bạn thân để chọc thử server}. We’ll use it throughout the series {Ta sẽ dùng nó xuyên suốt series}.
Mistakes beginners make {Lỗi người mới hay mắc}
- ❌ Confusing IP (machine) with port (program) {Nhầm IP (máy) với port (chương trình)}.
- ❌ Expecting TCP to preserve message boundaries — it’s a byte stream, not a message queue (Part 8) {Tưởng TCP giữ ranh giới message — nó là luồng byte, không phải hàng đợi message}.
- ❌ Binding a server to a privileged port (
< 1024) and hitting “permission denied” {Bind server vào port đặc quyền rồi gặp “permission denied”}. - ❌ Assuming
localhostand your LAN IP are the same —127.0.0.1is loopback only {Tưởnglocalhostvà IP LAN giống nhau —127.0.0.1chỉ là loopback}.
Exercises {Bài tập}
Try each before opening the solution {Thử từng bài trước khi mở lời giải}.
- Run the server above and connect with both
nc localhost 3000andtelnet localhost 3000{Chạy server trên và kết nối bằng cảncvàtelnet}. - Change the port to
80and explain the error you get (without sudo) {Đổi port sang80và giải thích lỗi nhận được}. - Use
curl -v http://localhost:3000and describe why the output looks odd {Dùngcurl -vvà mô tả vì sao output trông lạ}.
Solution {Lời giải}
node server.js
nc localhost 3000 # → Hello from the server!
telnet localhost 3000 # same greeting, then connection closesBinding to port 80 without privileges throws EACCES: permission denied because ports below 1024 are reserved for the OS / root {Bind port 80 không có quyền sẽ ném EACCES vì port dưới 1024 dành cho OS/root}.
curl -v http://localhost:3000 speaks HTTP, but our server replies with a plain greeting, not a valid HTTP response {curl nói HTTP, nhưng server của ta trả lời bằng lời chào thường, không phải HTTP hợp lệ}. curl prints the raw bytes and complains the response is malformed — a perfect preview of Part 5, where we speak real HTTP over the socket {curl in byte thô và phàn nàn response sai định dạng — màn dạo đầu hoàn hảo cho Phần 5}.
Takeaway {Điều cốt lõi}
Data travels as packets across layers; you address a program with an IP + port; a server waits, a client connects {Dữ liệu đi dạng packet qua các tầng; bạn định địa chỉ một chương trình bằng IP + port; server chờ, client kết nối}. With this model in hand, opening a real TCP socket in Part 2 will feel obvious {Có mô hình này, mở socket TCP thật ở Phần 2 sẽ thấy hiển nhiên}.