19 คะแนน โดย GN⁺ 2025-11-16 | 1 ความคิดเห็น | แชร์ทาง WhatsApp
  • TCP (Transmission Control Protocol) คือโปรโตคอลหลักของอินเทอร์เน็ตที่ทำให้ การส่งข้อมูลที่เชื่อถือได้และรับประกันลำดับ เป็นไปได้ แม้อยู่ในสภาพแวดล้อมเครือข่ายที่ไม่เสถียร
  • ขณะที่ IP รับผิดชอบเพียงการส่งข้อมูลระหว่างโฮสต์ TCP จะทำหน้าที่ การสื่อสารระหว่างโปรเซสบนพื้นฐานของพอร์ต รวมถึง การกู้คืนข้อผิดพลาด การส่งซ้ำ และการควบคุมลำดับ
  • ผ่าน การควบคุมการไหล (flow control) และ การควบคุมความแออัด (congestion control) เพื่อปรับไม่ให้เกินขีดจำกัดของบัฟเฟอร์ฝั่งรับหรือแบนด์วิดท์เครือข่าย
  • อธิบายขั้นตอนการสร้างซ็อกเก็ต การ bind การ listen การรับการเชื่อมต่อ และการรับส่งข้อมูลอย่างเป็นรูปธรรม ผ่าน ตัวอย่าง TCP server แบบง่ายและ HTTP server ที่เขียนด้วยภาษา C
  • โครงสร้างภายในของ TCP เช่น หมายเลข sequence และ ACK, window, checksum, flags (SYN/ACK/FIN/RST) เป็นรากฐานสำคัญที่ทำให้อินเทอร์เน็ตทำงานได้อย่างเสถียรในปัจจุบัน

ความจำเป็นและบทบาทของ TCP

  • IP รับผิดชอบเพียงการส่งแพ็กเก็ตระหว่างโฮสต์เท่านั้น และสำหรับ การสื่อสารระหว่างโปรเซส จำเป็นต้องมี ชั้นขนส่ง อย่าง TCP/UDP
    • เปรียบ IP address เป็น ‘อาคาร’ และพอร์ตเป็น ‘อพาร์ตเมนต์’ โดยแต่ละแอปพลิเคชันจะ bind กับพอร์ตเพื่อสื่อสาร
  • TCP ซ่อนความไม่เสถียรของเครือข่าย เช่น แพ็กเก็ตสูญหาย ซ้ำซ้อน หรือสลับลำดับ และรับประกันความเชื่อถือได้ผ่าน การส่งซ้ำและ checksum
  • เราเตอร์จึงคงความเรียบง่ายไว้ได้ และ ความเชื่อถือได้จะถูกจัดการที่ปลายทั้งสองด้านของการสื่อสาร เพื่อลดความซับซ้อนของโครงสร้างพื้นฐานเครือข่าย
  • ด้วยโครงสร้างนี้ บริการอินเทอร์เน็ตสำคัญอย่าง HTTP, SMTP, SSH จึงทำงานได้อย่างเสถียร

การควบคุมการไหลและการควบคุมความแออัด

  • ฝั่งรับจะเก็บข้อมูลชั่วคราวผ่าน receive buffer ของเคอร์เนล โดยขนาดบัฟเฟอร์ตั้งค่าได้ด้วย net.ipv4.tcp_rmem
  • ฝั่งส่งจะปรับปริมาณการส่งตามข้อมูลปริมาณข้อมูลที่ฝั่งรับยอมรับได้ ซึ่งถูกส่งมาผ่านฟิลด์ window
  • เพื่อป้องกัน ความแออัด (congestion) ที่เกิดจากความแตกต่างของแบนด์วิดท์ทั้งเครือข่าย TCP จึงนำ อัลกอริทึมควบคุมความแออัด มาใช้
    • เหตุการณ์ congestion collapse ในปี 1986 เป็นจุดเปลี่ยนที่ทำให้มีการเพิ่มกลไก back-off

ตัวอย่าง TCP server และ HTTP server

  • TCP echo server พื้นฐาน ที่เขียนด้วยภาษา C จะรับอินพุตจากไคลเอนต์ แล้วส่งกลับโดยเติม “you sent:” นำหน้า
    • ใช้ Berkeley sockets API เช่น socket(), bind(), listen(), accept(), send(), recv()
    • ระหว่างที่เซิร์ฟเวอร์อยู่ใน sleep() ข้อมูลจากไคลเอนต์จะ รออยู่ใน receive buffer และถูกประมวลผลตามลำดับภายหลัง
  • ในตัวอย่าง HTTP/1.1 server แบบง่าย จะรับคำขอผ่านการเชื่อมต่อ TCP แล้วส่ง header HTTP/1.1 200 OK และเนื้อหากลับไป
    • นับจำนวนคำขอด้วย i และเมื่อเรียก curl localhost:8080 จะได้การตอบกลับในรูปแบบ “[1] Yo, I am a legit web server”

โครงสร้างของ TCP segment และฟิลด์สำคัญ

  • TCP segment ประกอบด้วย พอร์ตต้นทาง/ปลายทาง, หมายเลข sequence, หมายเลข ACK, ขนาด window, checksum, flags เป็นต้น
    • พอร์ตถูกจัดสรรอย่างละ 16 บิต จึงใช้งานได้ สูงสุด 64K พอร์ต
    • การเชื่อมต่อถูกระบุด้วย 5-tuple ของ (protocol, source IP, source port, destination IP, destination port)
  • หมายเลข sequence แสดงช่วงไบต์ที่ถูกส่ง และ หมายเลข ACK แสดงไบต์ที่รับครบแล้ว
    • หากมีข้อมูลที่ขาดหาย ACK จะหยุดอยู่ที่จุดนั้น และจะอัปเดตเป็น cumulative ACK หลังการส่งซ้ำ
  • flag bits ใช้ควบคุมสถานะการเชื่อมต่อ
    • SYN/ACK ใช้สร้างการเชื่อมต่อผ่าน 3-way handshake
    • FIN ใช้ปิดการเชื่อมต่อผ่าน 4-way handshake
    • RST ใช้ยุติการเชื่อมต่อทันทีเมื่อเกิดการปิดแบบผิดปกติหรือข้อผิดพลาด
  • ฟิลด์ window ใช้ระบุปริมาณข้อมูลที่ยังรับได้ และสามารถตรวจสอบสถานะบัฟเฟอร์ (rb131072, tb16384) ได้ด้วยคำสั่ง ss
  • checksum ใช้ตรวจจับข้อผิดพลาดด้วยการรวมค่าใน segment ทีละ 16 บิต

บทสรุป

  • TCP รับประกัน ความเชื่อถือได้ ลำดับ และความสมบูรณ์ของข้อมูล ทำให้แอปพลิเคชันทำงานได้ตามปกติแม้อยู่บนอินเทอร์เน็ตที่ไม่เสถียร
  • หลายสิบปีก่อน การส่งข้อมูลเพียงไม่กี่ KB ยังเป็นเรื่องยาก แต่ปัจจุบันพัฒนาไปไกลจน การสตรีม 4K กลายเป็นเรื่องปกติ
  • ความประณีตในการออกแบบและการนำไปใช้จริงของ TCP ที่ทำให้การสื่อสารเสถียรเช่นนี้ได้ คือรากฐานของการเติบโตอย่างต่อเนื่องของอินเทอร์เน็ต

1 ความคิดเห็น

 
GN⁺ 2025-11-16
ความคิดเห็นจาก Hacker News
  • ถ้าพยายามสร้างสตรีมข้อมูลที่เชื่อถือได้บน ชั้น datagram ที่ไม่เชื่อถือได้ ผลลัพธ์สุดท้ายก็จะออกมาคล้าย TCP แทบทั้งหมด
    ข้อจำกัดช่วงแรกของ TCP คือ ขนาดหน้าต่าง ที่เล็ก การจัดการแพ็กเก็ตสูญหายที่ยังไม่ดีพอ และการรองรับเพียงสตรีมเดียว
    เพื่อแก้ปัญหาเหล่านี้จึงมี SCTP และ QUIC เกิดขึ้น
    อัลกอริทึมควบคุมความคับคั่งไม่ใช่ส่วนหนึ่งของโปรโตคอล แต่เป็นโค้ดที่ทำงานอยู่ทั้งสองฝั่งของแต่ละการเชื่อมต่อ
    อัลกอริทึมยุคแรก ๆ (เช่น Reno, Vegas) เรียบง่ายแต่มีประสิทธิภาพเพียงพอ และหลังจากนั้นก็มีงานวิจัยต่อเนื่องเกี่ยวกับบัฟเฟอร์ขนาดใหญ่, RTT ยาว, ความเป็นธรรม ฯลฯ

    • คิดว่านักพัฒนาเว็บเองก็มีส่วนที่ใช้มัลติสตรีมได้ไม่ดีนัก
      เมื่อก่อนเคยทำไลบรารี JavaScript ที่ควบคุม การจัดลำดับความสำคัญและการยกเลิก ของหลายดาวน์โหลดผ่านสตรีมเดียวได้
      เคยใช้สคริปต์ GreaseMonkey ให้เว็บหาคู่โหลดภาพ thumbnail ล่วงหน้าในพื้นหลัง และพรีโหลดตามตำแหน่งการเลื่อนหน้าจอ
      ผลคือช่วยลดภาระเซิร์ฟเวอร์พร้อมกับทำให้ประสบการณ์ใช้งานดีขึ้น
      ที่ตลกคือเคยแชร์สคริปต์นั้นให้กับแมตช์คนหนึ่ง และทุกวันนี้ก็ยังคบกันอยู่ — เรียกได้ว่าเป็น Tinder ก่อนยุค Tinder เลย
    • ตอนที่ TCP ถูกสร้างขึ้น แนวคิดแบบ การสลับวงจร (circuit switching) ที่ยึดเครือข่ายโทรศัพท์เป็นศูนย์กลางยังครอบงำอยู่
      TCP เป็นโครงสร้างที่ให้วงจรเสมือนบนเครือข่ายสลับแพ็กเก็ต และแนวคิดเรื่องความเชื่อถือได้ที่ทำผ่าน การส่งซ้ำ นั้นมีต้นกำเนิดจากเครือข่าย Cylades ของฝรั่งเศส
    • หนึ่งในข้อบกพร่องพื้นฐานของ TCP คือ ไม่สามารถทำให้ปลอดภัยได้
      ผู้โจมตีสามารถ inject ข้อมูลจากที่ใดก็ได้ในเครือข่าย หรือปิดการเชื่อมต่อด้วย แพ็กเก็ต RST
      การบล็อก RST ด้วยไฟร์วอลล์ช่วยเพิ่มเสถียรภาพได้ แต่ การโจมตีแบบ desynchronization จากหมายเลขลำดับปลอมก็ยังเป็นไปได้อยู่
      ดังนั้นทุกแอปพลิเคชันจึงต้องทำ ฟังก์ชัน resume เองบนการเชื่อมต่อแยกต่างหาก และยังต้องแบกรับปัญหา slow start ของ TCP ไปด้วย
      อีกทั้งยังมองว่าแนวคิดที่แยก address ออกจาก port เองก็ไม่มีประสิทธิภาพ
    • แอปพลิเคชันบางประเภททำงานได้ดีมากแม้ใช้การเชื่อมต่อ TCP เพียงเส้นเดียว
      ตัวอย่างเช่นใน DNS over TLS(DoT) สามารถส่งหลาย query พร้อมกันผ่าน TCP connection เดียวและรับคำตอบ แบบไม่ต้องเรียงลำดับ ได้
      วิธีนี้มีประสิทธิภาพกว่าและสุภาพกว่าการเปิดหลายการเชื่อมต่อ
      QUIC จะเร็วกว่าไหมยังไม่แน่ใจ แต่ฝั่งเซิร์ฟเวอร์ยังรองรับอย่างจำกัด
      HTTP/1.1 pipelining ก็ทำอะไรคล้ายกันได้ แต่การตอบกลับจะมาแบบตามลำดับ
    • การที่ อัลกอริทึมควบคุมความคับคั่ง ของ TCP อยู่นอกตัวโปรโตคอลเอง ถือว่านวัตกรรมมากในยุคนั้น
      แต่ในหลายวิชามหาวิทยาลัยกลับไม่เน้นจุดนี้ ทำให้หลายคนเข้าใจผิดว่า TCP มีอัลกอริทึมเดียว
  • อยากถามว่ามีใครชอบ SCTP เป็นพิเศษไหม
    SCTP เป็นโปรโตคอลที่ผสานการสื่อสารแบบ message-oriented ของ UDP เข้ากับความเชื่อถือได้ของ TCP และรองรับ multistreaming กับ multihoming
    มันส่งหลายสตรีมอิสระแบบขนานได้ จึงสามารถส่งทั้งข้อความและรูปภาพของเว็บเพจพร้อมกันได้
    ดูรายละเอียดได้ที่ Wikipedia: Stream Control Transmission Protocol

    • SCTP แก้ปัญหาได้แค่ครึ่งเดียว และยังเพิ่มข้อบกพร่องใหม่เข้ามาอีกหลายอย่าง
      ท้ายที่สุดคำตอบที่ดีที่สุดคือ ชั้นความเชื่อถือได้บน UDP หรือก็คือ QUIC
    • ในฐานะคนที่ใช้ BSD เป็นประจำและทำงานด้วย Erlang ผมรัก SCTP มาก
  • เคยสงสัยว่าสามารถส่งแพ็กเก็ตโดยใช้แค่ IP ตรง ๆ ได้ไหม
    รู้สึกว่าระหว่างทางเราเตอร์น่าจะปฏิเสธแพ็กเก็ตที่ไม่ใช่ TCP หรือ UDP

    • สามารถ จัดการและส่งแพ็กเก็ต IP โดยตรง ได้
      ถ้าเป็น IPv4 ก็แค่ระบุหมายเลขหนึ่งในช่วง 0~255 จาก รายการหมายเลขโปรโตคอลของ IANA
      เราเตอร์แกนหลักจะไม่ตรวจฟิลด์นี้ แต่ NAT หรืออุปกรณ์ของ ISP อาจตรวจ
      ระหว่าง Linux server สองเครื่องก็สามารถสื่อสารด้วยหมายเลขทดลอง (253, 254) ได้
    • อย่าลืม ICMP ด้วย โดยเฉพาะใน IPv6 ยิ่งสำคัญ
      โปรโตคอลอย่าง IPsec, GRE, L2TP ก็ไม่ใช่ TCP/UDP
      ในสภาพแวดล้อมที่เป็นไฟร์วอลล์หรือ NAT ของเครือข่ายองค์กร โปรโตคอลตามอำเภอใจอาจถูกบล็อกได้
      NAT ได้ทำลาย หลักการ end-to-end และสุดท้ายผู้คนก็เริ่มวางทุกอย่างไว้บน TCP หรือ UDP หรือแม้แต่ บน HTTP
    • ถ้าไม่มี NAT หรือ load balancer ก็ไม่มีปัญหา แต่ทุกวันนี้สิ่งเหล่านี้พบได้ทั่วไป จึงอาจเป็นไปได้ว่า IPv6 ดีกว่า
    • เราเตอร์เป็น อุปกรณ์ชั้น 3 จึงไม่สนใจว่าเป็น TCP/UDP หรือไม่
      มีผลแค่ทำให้ entropy ของ ECMP hash ลดลงบ้างเท่านั้น
      สุดท้ายประเด็นคือปลายทางเข้าใจโปรโตคอลนั้นหรือไม่
    • TCP และ UDP เป็นเพียง IP payload เท่านั้น และเราเตอร์ไม่ได้ตีความมัน
      หมายเลขพอร์ตก็เป็นเพียง ตัวระบุบริการภายในโหนด เท่านั้น
  • RUDP(Plan9) เป็นทางสายกลางที่ยอดเยี่ยมระหว่าง TCP กับ UDP
    ดู Reliable User Datagram Protocol

  • เพราะ TCP กลายเป็นค่าเริ่มต้น จึงถูกใช้แบบอัตโนมัติแม้ในกรณีที่ไม่ต้องการทั้งความเชื่อถือได้หรือการรับประกันลำดับ
    ตอนนี้เมื่อ HTTP/3 (บนพื้นฐาน QUIC) เริ่มแพร่หลาย สถานการณ์อาจดีขึ้น
    เพียงแต่ QUIC ซับซ้อนกว่ามาก และพลังของมันมีประโยชน์กับคนบางกลุ่มเท่านั้น
    UDP + ชั้นเข้ารหัสแบบเรียบง่ายสไตล์ WireGuard อาจเป็นทางเลือกที่ดีกว่า

  • TCP เป็นหนึ่งในสิ่งประดิษฐ์อันยิ่งใหญ่ของมนุษยชาติ แต่ไม่ได้คาดการณ์การครอบงำของ เครือข่ายกึ่งเชื่อมต่อ (แบบอิง NAT)

    • มีคนถามขึ้นมาว่า “หมายถึง NAT ใช่ไหม?”
    • ถ้าย้อนกลับไปปี 1981 แล้วบอกว่า “แทนที่จะใช้ address ที่เข้าถึงได้ทั่วโลก เรามาใช้ address ช่วงจำกัด และทำให้บางโหนดเข้าไม่ถึงกันเถอะ”
      วิศวกรในยุคนั้นก็คงถามว่าทำไมต้องทำให้ซับซ้อนแบบนั้น
      ท้ายที่สุดโครงสร้างลิงก์แบบ อสมมาตร และการแบ่งฝั่ง client–server ในปัจจุบันก็มาจากแนวคิดแบบนี้
  • อัลกอริทึมควบคุมความคับคั่ง ของ TCP มีผลที่น่าสนใจซึ่งนักพัฒนาจำนวนมากไม่ค่อยรู้
    เมื่อส่งข้อมูลบนการเชื่อมต่อใหม่ การส่งช่วงแรกจะช้า และการเพิ่มความเร็วขึ้นจะถูกกำหนดโดย latency
    ในดาต้าเซ็นเตอร์ แค่ลด RTT ลงไม่กี่ไมโครวินาทีก็เพิ่มความเร็วได้มาก
    TCP stack ส่วนใหญ่คำนวณการไต่ความเร็วเป็น หน่วยเซกเมนต์ ไม่ใช่ไบต์ ดังนั้นถ้าใช้ jumbo frame ก็อาจไต่ขึ้นได้เร็วกว่า 6 เท่า
    ด้วยเหตุนี้ AWS จึงทุ่มเทอย่างมากกับ switching latency ต่ำ และ การรองรับ jumbo frame
    ผู้เชี่ยวชาญปรับแต่งเรื่องนี้กัน แต่คนส่วนใหญ่กลับสงสัยว่าทำไมลิงก์ 10Gbps ถึงวิ่งไม่ได้ 10Gbps

  • การสร้างโปรโตคอลของตัวเองบน IP เคยเป็นเรื่องที่ ง่ายมาก
    แค่เมื่อ 15 ปีก่อนก็ยังทดลองด้วย Python โดย ประกอบแพ็กเก็ตเองโดยตรง ได้