เซิร์ฟเวอร์ TCP
ยอมรับการเชื่อมต่อ
เซิร์ฟเวอร์ TCP เป็นบทเรียน C Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน C Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส C Academy มีบทเรียนทั้งหมด 4 บทเรียน
การสร้างเซิร์ฟเวอร์ TCP
เซิร์ฟเวอร์ TCP จะรอไคลเอนต์และรับการเชื่อมต่อของไคลเอนต์ วงจรการทำงานคือ สร้างซ็อกเก็ต ผูกเข้ากับพอร์ต รอรับการเชื่อมต่อ แล้วรับการเชื่อมต่อภายในลูป
ขั้นตอนที่ 1: สร้างซ็อกเก็ต
สร้างซ็อกเก็ตแบบสตรีมสำหรับ IPv4 TCP หากผลลัพธ์เป็นค่าลบ แสดงว่าเกิดความล้มเหลว
#include <sys/socket.h>
#include <stdio.h>
int make_server_socket(void) {
int fd = socket(AF_INET, SOCK_STREAM, 0);
if (fd < 0) { perror("socket"); }
return fd;
}ขั้นตอนที่ 2: อนุญาตให้ใช้ที่อยู่ซ้ำ
ตามค่าเริ่มต้น พอร์ตจะค้างอยู่ในสถานะ TIME_WAIT หลังจากเซิร์ฟเวอร์หยุดทำงาน ทำให้เริ่มการทำงานใหม่ไม่ได้ ให้กำหนด SO_REUSEADDR ด้วย setsockopt เพื่อให้ผูกพอร์ตใหม่ได้ทันที
#include <sys/socket.h>
void allow_reuse(int fd) {
int yes = 1;
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof yes);
}ขั้นตอนที่ 3: ผูกกับพอร์ต
bind() ผูกซ็อกเก็ตเข้ากับที่อยู่และพอร์ตภายในเครื่อง INADDR_ANY จะทำให้รอรับการเชื่อมต่อจากอินเทอร์เฟซเครือข่ายทั้งหมด
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
int bind_port(int fd, unsigned short port) {
struct sockaddr_in addr = {0};
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_port = htons(port);
if (bind(fd, (struct sockaddr *)&addr, sizeof addr) < 0) {
perror("bind"); return -1;
}
return 0;
}ขั้นตอนที่ 4: รอรับการเชื่อมต่อ
listen() กำหนดให้ซ็อกเก็ตอยู่ในโหมดรอรับ (พร้อมรับการเชื่อมต่อ) อาร์กิวเมนต์ backlog กำหนดจำนวนการเชื่อมต่อที่รอดำเนินการซึ่งเคอร์เนลสามารถเข้าคิวไว้ได้
#include <sys/socket.h>
#include <stdio.h>
int start_listen(int fd) {
if (listen(fd, 16) < 0) { /* backlog of 16 */
perror("listen"); return -1;
}
return 0;
}ขั้นตอนที่ 5: รับการเชื่อมต่อ
accept() จะหยุดรอจนกว่าไคลเอนต์จะเชื่อมต่อ จากนั้นคืนค่าซ็อกเก็ตใหม่สำหรับไคลเอนต์นั้น ซ็อกเก็ตเดิมยังคงรอรับการเชื่อมต่อต่อไป
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
int accept_one(int listen_fd) {
struct sockaddr_in cli;
socklen_t len = sizeof cli;
int conn = accept(listen_fd, (struct sockaddr *)&cli, &len);
if (conn < 0) perror("accept");
return conn;
}ซ็อกเก็ตสองตัว บทบาทสองแบบ
หลังจากเรียก accept คุณจะมีซ็อกเก็ตสองตัว:
- ซ็อกเก็ตรอรับการเชื่อมต่อยังคงรับไคลเอนต์ใหม่
- ซ็อกเก็ตการเชื่อมต่อใช้สื่อสารกับไคลเอนต์ที่ระบุหนึ่งราย
เมื่อสื่อสารกับไคลเอนต์รายนั้นเสร็จแล้ว ให้ปิดซ็อกเก็ตการเชื่อมต่อ
การอ่านคำขอ
ใช้ recv เพื่ออ่านข้อมูลจากไคลเอนต์ลงในบัฟเฟอร์ หากคืนค่า 0 หมายความว่าไคลเอนต์ยกเลิกการเชื่อมต่อแล้ว ส่วน -1 หมายถึงเกิดข้อผิดพลาด
#include <sys/socket.h>
#include <stdio.h>
void handle(int conn) {
char buf[256];
ssize_t n = recv(conn, buf, sizeof buf - 1, 0);
if (n > 0) { buf[n] = 0; printf("got: %s\n", buf); }
}การส่งการตอบกลับ
ตอบกลับด้วย send สำหรับข้อมูลขนาดใหญ่ ให้วนซ้ำจนกว่าจะส่งไบต์ทั้งหมด เนื่องจากการเรียกใช้เพียงครั้งเดียวอาจเขียนข้อมูลในบัฟเฟอร์ได้เพียงบางส่วน
#include <sys/socket.h>
#include <string.h>
void reply(int conn) {
const char *msg = "hello from server\n";
size_t left = strlen(msg);
const char *p = msg;
while (left > 0) {
ssize_t n = send(conn, p, left, 0);
if (n <= 0) break;
p += n; left -= (size_t)n;
}
}ลูปรับการเชื่อมต่อ
เซิร์ฟเวอร์แบบวนซ้ำอย่างง่ายจะรับไคลเอนต์หนึ่งราย ให้บริการ ปิดการเชื่อมต่อ แล้ววนกลับไปรับไคลเอนต์รายถัดไป เซิร์ฟเวอร์จะจัดการไคลเอนต์ทีละราย
#include <unistd.h>
void serve_loop(int listen_fd, int (*accept_one)(int), void (*handle)(int)) {
for (;;) {
int conn = accept_one(listen_fd);
if (conn < 0) continue;
handle(conn);
close(conn); /* done with this client */
}
}การปิดระบบอย่างเรียบร้อย
ปิดซ็อกเก็ตที่รอรับการเชื่อมต่อเมื่อเซิร์ฟเวอร์หยุดทำงาน และจัดการ SIGINT เพื่อออกจากลูปอย่างเรียบร้อย ต้องปิดเดสคริปเตอร์เสมอเพื่อคืนทรัพยากรของเคอร์เนล
ตรวจสอบความเข้าใจอย่างรวดเร็ว
ทดสอบความเข้าใจของคุณเกี่ยวกับเซิร์ฟเวอร์ TCP
สรุปทบทวน
คุณได้สร้างเซิร์ฟเวอร์ TCP ทีละขั้นตอน
- socket จากนั้น SO_REUSEADDR แล้วจึง bind, listen, accept
acceptคืนค่าซ็อกเก็ตใหม่สำหรับไคลเอนต์แต่ละราย- ใช้ recv/send เพื่อสื่อสาร แล้วปิดการเชื่อมต่อ
- ใช้ลูปเพื่อให้บริการไคลเอนต์ และตรวจสอบค่าที่ส่งคืนทุกครั้ง
คำถามที่พบบ่อย
บทเรียน “เซิร์ฟเวอร์ TCP” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “เซิร์ฟเวอร์ TCP” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส C Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส C Academy มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “เซิร์ฟเวอร์ TCP”
ยอมรับการเชื่อมต่อ คุณปฏิบัติ C Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน C Academy หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน C Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน
บทเรียน “เซิร์ฟเวอร์ TCP” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน C Academy นี้ได้ไหม
ได้ บทเรียน C Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- ภาพรวมซ็อกเก็ต
- เซิร์ฟเวอร์ TCP
- ไคลเอ็นต์ TCP
- การจัดการไคลเอ็นต์หลายราย