0Pricing
C Academy · บทเรียน

เซิร์ฟเวอร์ 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 ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. ภาพรวมซ็อกเก็ต
  2. เซิร์ฟเวอร์ TCP
  3. ไคลเอ็นต์ TCP
  4. การจัดการไคลเอ็นต์หลายราย
← กลับไปที่ C Academy