Socket API — จุดเชื่อมระหว่างแอปกับเครือข่าย
Socket API คือจุดที่แนวคิดเรื่อง address, port, transport, buffer และ connection กลายเป็นคำสั่งที่โปรแกรมเรียกใช้จริง แต่คำว่า send, receive และ connected ในมุมของระบบปฏิบัติการ ไม่ได้หมายถึงความสำเร็จระดับ application เสมอไป
1Socket คืออะไร
Application ไม่ได้สร้าง TCP segment หรือ IP packet ด้วยตนเองทุกครั้ง โดยทั่วไปมันขอให้ระบบปฏิบัติการจัดการผ่าน Socket API ซึ่งทำหน้าที่เป็น interface ระหว่าง process กับบริการสื่อสารที่ระบบมีให้
Socket เป็นทั้งแนวคิดและทรัพยากรของระบบปฏิบัติการ
ในโปรแกรมแบบ Unix-like การเรียก socket() คืนค่า file descriptor ซึ่งเป็นหมายเลขที่ process ใช้อ้างถึง socket object ที่ kernel ดูแลอยู่ ข้างใน object นี้มี state, buffer, protocol information และข้อมูล address ที่เกี่ยวข้อง ตัวเลข descriptor ไม่ใช่ port และไม่ใช่หมายเลข connection บนเครือข่าย เป็นเพียง handle ภายใน process
Process สองตัวอาจมี descriptor หมายเลข 3 เหมือนกันได้ เพราะแต่ละ process มีตาราง descriptor ของตนเอง เช่นเดียวกับห้อง 3 ในคนละอาคารไม่ใช่ห้องเดียวกัน การดูตัวเลขเพียงค่าเดียวโดยไม่ดูขอบเขตจึงตีความไม่ได้
Address Family, Socket Type และ Protocol
| พารามิเตอร์ | ตัวอย่าง | กำหนดอะไร |
|---|---|---|
| Address Family | AF_INET, AF_INET6, AF_UNIX | รูปแบบ address และขอบเขตการสื่อสาร เช่น IPv4, IPv6 หรือ Unix-domain communication ภายในเครื่อง |
| Socket Type | SOCK_STREAM, SOCK_DGRAM | ลักษณะบริการที่ API นำเสนอ เช่น byte stream หรือ message-oriented datagram |
| Protocol | 0, IPPROTO_TCP, IPPROTO_UDP | เลือก protocol เฉพาะ เมื่อ family กับ type ยังรองรับได้มากกว่าหนึ่งตัว หรือระบุให้ชัดเจน |
ใน API ดั้งเดิมจะพบทั้งชื่อ AF_* และ PF_* โดยทั่วไปโปรแกรมใช้ AF_INET หรือ AF_INET6 เป็น address family ส่วนการใช้ AF_INET + SOCK_STREAM + protocol 0 มักเลือก TCP ตามค่าเริ่มต้นของระบบ
int fd = socket(AF_INET, SOCK_STREAM, 0);
คำสั่งนี้ขอ Internet-domain stream socket ซึ่งโดยทั่วไปหมายถึง TCP/IPv4 หากสำเร็จ เราได้ descriptor สำหรับอ้างถึง socket แต่ยังไม่ได้แปลว่าเชื่อมกับ server ใดแล้ว ขั้นตอนสร้าง object กับขั้นตอนสร้าง network connection เป็นคนละเรื่อง
AF_UNIX หรือ AF_LOCAL ใช้ Unix-domain socket สำหรับ inter-process communication ภายในเครื่อง ไม่ใช่ Unix pipe แม้ทั้งคู่ช่วยให้ process สื่อสารกันได้ ส่วน packet socket เช่น AF_PACKET เป็นความสามารถเฉพาะบางระบบอย่าง Linux ใช้เข้าถึง frame ระดับ link และต้องมีสิทธิ์เหมาะสม จึงไม่ใช่เส้นทางปกติของ application ทั่วไป
IP Address บอกเครื่อง ส่วน Port ช่วยบอก Process หรือ Service
IP address ช่วยพาข้อมูลไปยัง host หรือ interface ตามขอบเขตของ network routing ส่วน port number ช่วยให้ Transport Layer ส่งข้อมูลต่อไปยัง socket ของ process ที่เหมาะสมบน host นั้น จึงอาจมอง address กับ port เป็น “ที่อยู่สองระดับ”
Connection หนึ่งชุดถูกแยกจาก connection อื่นอย่างไร
TCP connection มักระบุได้ด้วยข้อมูล 4 ค่า ได้แก่ source IP, source port, destination IP และ destination port หากรวม transport protocol เข้าไปด้วย มักพูดถึง 5-tuple ข้อมูลชุดนี้ทำให้ server ใช้ local port เดียวรับ client จำนวนมากได้ โดยแต่ละ connection ยังแยกจากกัน
| ค่า | ตัวอย่าง | หน้าที่ |
|---|---|---|
| Protocol | TCP | บอกกติกาการขนส่งที่ใช้ |
| Source IP:Port | 192.0.2.10:53124 | ระบุ endpoint ฝั่ง client ใน connection นี้ |
| Destination IP:Port | 198.51.100.20:443 | ระบุ endpoint ของ service ปลายทาง |
Client มักปล่อยให้ระบบปฏิบัติการเลือก ephemeral port ชั่วคราวให้ ส่วน server เลือก port ที่ผู้ใช้หรือระบบค้นพบได้ Port 0–1023 เป็น well-known range ตามธรรมเนียมและข้อกำหนดของระบบ แต่ server ของเราใช้ registered หรือ dynamic/private port อื่นก็ได้ หาก client รู้ว่าจะติดต่อที่ใด
วงจรชีวิตของ socket ไม่ได้มีเพียงสี่คำสั่ง
ลำดับ operation ขึ้นกับชนิด socket และบทบาท TCP server, TCP client และ UDP endpoint ใช้ขั้นตอนไม่เหมือนกัน การสรุปเป็น create → attach → send/receive → close ช่วยเห็นภาพกว้าง แต่ยังไม่พอสำหรับเขียนโปรแกรมจริง
2TCP Client-Server Flow (ภาพรวม)
TCP เป็น connection-oriented byte stream ฝั่ง server เตรียมจุดรับ connection ส่วน client เริ่มเชื่อมต่อ เมื่อ handshake สำเร็จทั้งสองฝั่งจึงส่ง byte ผ่าน connection ได้ แต่ socket ที่ใช้รอรับกับ socket ที่ใช้คุยกับ client แต่ละรายเป็นคนละ object
| ฝั่ง | เรียกฟังก์ชัน | ความหมาย |
|---|---|---|
| Server (Passive Open) | bind() | กำหนด local address และ port ที่ socket จะใช้รับการเชื่อมต่อ อาจ bind ทุก local interface หรือเจาะจง interface |
listen() | เปลี่ยน socket เป็น listening socket และให้ค่า backlog เป็นคำขอหรือขอบเขตของคิว connection ที่รอ ระบบปฏิบัติการอาจปรับหรือจำกัดค่าจริง | |
accept() | รับ connection ที่พร้อมแล้วและคืน connected socket ใหม่ สำหรับ client รายหนึ่ง ส่วน listening socket เดิมยังเปิดรอ client รายต่อไป | |
| Client (Active Open) | connect() | เริ่มสร้าง connection ไปยัง endpoint ปลายทาง ใน blocking mode มักรอจนสำเร็จ ล้มเหลว หรือ timeout ส่วน non-blocking mode อาจคืนค่าก่อน handshake เสร็จ |
| ทั้งสองฝั่ง | send() / recv() | เขียน byte ลงและอ่าน byte จาก socket buffer ตาม state ของ connection ไม่ได้รับประกันว่าจะจัดการข้อมูลครบตามขนาดที่ application ขอใน call เดียว |
| ทั้งสองฝั่ง | shutdown() / close() | ปิดทิศทางการสื่อสารบางด้านหรือปล่อย descriptor และเริ่มขั้นตอนปิด connection ตาม semantics ของระบบ |
Listening Socket กับ Connected Socket
Server เริ่มจาก listening socket หนึ่งตัว เมื่อ accept() สำเร็จ ระบบคืน connected socket อีกตัวสำหรับคุยกับ client รายนั้น Server จึงมี socket สองบทบาทพร้อมกัน: ตัวหนึ่งรับแขกใหม่ อีกหลายตัวดูแลแขกที่เข้ามาแล้ว
Blocking ไม่ได้แปลว่าโปรแกรมทั้งระบบต้องหยุด
ใน blocking mode คำสั่งอย่าง accept() หรือ recv() อาจรอจนมีเหตุการณ์ที่ต้องการ แต่สิ่งที่หยุดคือ thread ที่เรียก operation นั้น ไม่จำเป็นต้องเป็น process ทั้งหมด Server สามารถใช้หลาย thread, หลาย process, event loop หรือ asynchronous I/O เพื่อดูแลหลาย connection พร้อมกัน
แต่ละแนวทางมีต้นทุนต่างกัน Thread-per-connection เข้าใจง่ายแต่ใช้ทรัพยากรเพิ่มเมื่อ connection จำนวนมาก Event-driven model รองรับ connection ได้มากโดยใช้ thread น้อย แต่ state ของแต่ละ connection และ error path ซับซ้อนขึ้น ไม่มี concurrency model ที่ดีที่สุดโดยไม่ดู workload
connect() สำเร็จรับรองถึงระดับใด
TCP connect สำเร็จหมายถึง transport connection ถูกสร้างกับ endpoint ปลายทางตาม protocol ไม่ได้หมายความว่า application ปลายทาง authenticate ผู้ใช้แล้ว ทำ transaction เสร็จแล้ว หรือแม้แต่พร้อมตอบ request ที่เรากำลังจะส่ง Server process อาจ accept connection แล้วแต่ติดคิวงานภายในอีกนาน
ในทางกลับกัน connect ล้มเหลวอาจให้หลักฐานต่างกัน เช่น connection refused ชี้ว่าปลายทางตอบกลับแต่ไม่มี service รับตามเงื่อนไขนั้น ขณะที่ timeout อาจเกิดจาก packet ถูกกรอง เส้นทางขาด หรือปลายทางเงียบ การแปล error code ต้องดูขอบเขต ไม่ควรสรุปว่า “server ล่ม” จากอาการเดียว
3send(), recv() และสิ่งที่ Programmer มักเข้าใจเกินจริง
TCP เป็น Byte Stream ไม่ใช่ Message Stream
TCP รักษาลำดับ byte แต่ไม่รักษาขอบเขตของแต่ละ send() สมมุติ sender ส่ง “ABC” แล้วส่ง “DEF” receiver อาจอ่านได้ “ABCDEF” ครั้งเดียว หรืออ่าน “AB”, “CD”, “EF” หลายครั้งก็ได้ ตราบใดที่ลำดับ byte ยังถูกต้อง
ดังนั้น application protocol ต้องกำหนด message framing เอง เช่น:
| วิธี framing | แนวคิด | สิ่งที่ต้องระวัง |
|---|---|---|
| Fixed length | ทุก message ยาวเท่ากัน | ง่ายแต่ไม่เหมาะกับข้อมูลขนาดหลากหลาย และอาจเสียพื้นที่ |
| Delimiter | ใช้ตัวคั่น เช่น newline | ต้อง escape หรือห้ามตัวคั่นปรากฏใน payload โดยไม่ตั้งใจ |
| Length prefix | ส่งความยาวก่อน payload | ต้องรับ header ให้ครบ ตรวจขนาด และป้องกันค่าความยาวที่ผิดหรือเป็นอันตราย |
| Self-describing format | รูปแบบข้อมูลบอกจุดสิ้นสุดได้ | Parser ต้องรองรับข้อมูลไม่ครบและข้อมูลที่ไม่ถูกต้อง |
send() อาจส่งได้ไม่ครบตามที่ขอ
ค่า return ของ send() หรือ write() บอกจำนวน byte ที่ API รับไปในครั้งนั้น โดยเฉพาะ non-blocking socket หรือเมื่อ buffer มีพื้นที่จำกัด อาจรับได้น้อยกว่าขนาดที่ application ขอ Programmer จึงต้องวนส่งส่วนที่เหลือและจัดการ error อย่างถูกต้อง
แม้ส่งเข้า kernel buffer ได้ครบ ก็ยังไม่ได้รับรองว่า byte ถึง application ปลายทาง TCP จะพยายามส่งตาม state ของ connection แต่หากเครื่องหยุดทำงานหลังจากนั้นหรือ connection เกิดปัญหา ผลลัพธ์ระดับ application ยังอาจไม่สำเร็จ
recv() อาจได้ข้อมูลน้อยกว่าหนึ่ง Message
recv() คืน byte ที่พร้อมอ่านในขณะนั้น สูงสุดตามขนาด buffer ที่ application ให้ มันไม่จำเป็นต้องรอให้ “message ของเรา” ครบ เพราะ TCP ไม่รู้ขอบเขตดังกล่าว Application ต้องสะสมข้อมูลจน parser บอกว่าได้ frame ครบ
หาก recv() คืน 0 บน TCP โดยทั่วไปหมายถึง peer ปิดทิศทางการส่งอย่างเป็นระเบียบและเราอ่านข้อมูลที่ค้างหมดแล้ว ไม่ใช่ “ยังไม่มีข้อมูล” ส่วนกรณียังไม่มีข้อมูลใน non-blocking mode จะรายงานสถานะหรือ error ที่ต่างออกไปตาม API
send(fd, buf, 1000, ...) แล้วได้ค่า return 400 โปรแกรมควรทำอย่างไร? ต้องเก็บว่า 400 byte แรกถูก API รับไปแล้ว แล้วส่งต่อจาก byte ที่ 401 ไม่ใช่เริ่มส่ง 1,000 byte เดิมซ้ำทั้งหมด และไม่ควรถือว่า connection เสียทันทีเพียงเพราะเกิด partial write
Buffer ช่วยแยกจังหวะ แต่ไม่ได้มีขนาดไม่จำกัด
Send buffer ช่วยให้ application วางข้อมูลไว้แล้วกลับไปทำงานต่อ ขณะที่ kernel ค่อยส่งตามเครือข่าย Receive buffer เก็บข้อมูลที่มาถึงไว้จน application อ่าน ความเร็วของ application กับ network จึงไม่ต้องตรงกันทุกขณะ
แต่หาก sender สร้างข้อมูลเร็วกว่าที่ network ระบายออก buffer จะเต็มและ send() อาจ block, รับข้อมูลบางส่วน หรือรายงานให้ลองใหม่ หาก receiver อ่านช้า receive window อาจลดลงและ flow control ทำให้ sender ช้าตาม Buffer ดูดซับความต่างระยะสั้นได้ แต่ไม่สามารถแก้ความไม่สมดุลถาวร
Timeout เป็นนโยบายของผู้รอ ไม่ใช่หลักฐานว่าอีกฝั่งไม่ได้ทำงาน
เมื่อ operation timeout เรารู้เพียงว่าไม่เห็นผลที่ต้องการภายในเวลาที่กำหนด Request อาจไม่ถึง server, server อาจทำอยู่, response อาจหาย หรือระบบอาจเพียงช้ากว่าค่าที่เราตั้ง หาก retry operation ที่มีผลข้างเคียงโดยไม่มี idempotency อาจทำงานซ้ำ
การออกแบบจึงต้องแยก connect timeout, read timeout, write timeout และ deadline ของงานทั้งหมด เพราะแต่ละค่าป้องกันการรอคนละช่วง Deadline แบบ end-to-end ช่วยไม่ให้การ retry หลายรอบรวมกันยาวเกินเวลาที่ผู้ใช้ยอมรับ
close() กับ shutdown() และการปิดเพียงครึ่งทาง
close() ปล่อย descriptor ของ process เมื่อไม่มี reference ที่เกี่ยวข้องเหลือ ระบบจึงดำเนินการปิด socket ตาม semantics ของ protocol ส่วน shutdown() ใช้ปิดทิศทางการอ่านหรือเขียนบางด้านโดยไม่จำเป็นต้องปล่อย descriptor ทันที
TCP เป็น full-duplex จึงสามารถเกิด half-close ได้ เช่น client ส่ง request เสร็จแล้วปิดทิศทางเขียนเพื่อบอกว่าไม่มีข้อมูลเพิ่ม แต่ยังอ่าน response จาก server ต่อ การเข้าใจว่าปิดหนึ่งทิศไม่เท่ากับทำลายทุกอย่างทันทีช่วยออกแบบ protocol ที่ใช้ end-of-stream เป็นสัญญาณได้
4UDP Socket — ไม่มี Connection แต่ไม่ได้แปลว่าไม่มีกติกา
UDP ให้บริการแบบ datagram และรักษาขอบเขต message แต่ไม่สร้าง connection และไม่รับรอง delivery, ordering หรือ duplicate suppression ให้ Application จึงได้ overhead และ state ที่น้อยลง พร้อมรับผิดชอบคุณสมบัติที่ต้องการเพิ่มเติมเอง
| ประเด็น | TCP Stream Socket | UDP Datagram Socket |
|---|---|---|
| การเริ่มสื่อสาร | สร้าง connection ก่อนส่ง byte | ส่ง datagram ไปยัง address ปลายทางได้โดยไม่ handshake แบบ TCP |
| ขอบเขตข้อมูล | ไม่รักษาขอบเขตของ send() | รักษาขอบเขต datagram ใน API |
| Reliability/Ordering | ให้ byte stream ที่น่าเชื่อถือและเรียงลำดับตามขอบเขต TCP | ไม่รับรองว่าจะถึง ไม่ซ้ำ หรือเรียงลำดับ |
| API ที่พบบ่อย | connect, accept, send, recv | sendto, recvfrom และอาจใช้ connect เพื่อกำหนด default peer |
| ตัวอย่างงาน | Web, SSH, database connection | DNS query บางรูปแบบ, real-time media และ protocol ที่สร้างกลไกเพิ่มเอง |
UDP socket สามารถเรียก connect() ได้ แต่ไม่ได้สร้าง handshake หรือ reliability แบบ TCP โดยทั่วไปเป็นการบันทึก default peer ใน kernel และช่วยกรองหรือส่ง datagram โดยไม่ต้องระบุ address ทุกครั้ง คำว่า connected UDP จึงมีความหมายต่างจาก connected TCP
หนึ่ง recvfrom อ่านหนึ่ง Datagram แต่ Buffer อาจเล็กเกินไป
UDP รักษาขอบเขต datagram ต่างจาก TCP stream หาก sender ส่ง datagram สองก้อน receiver จะไม่เห็นเป็น byte stream ก้อนเดียว อย่างไรก็ตาม หาก receive buffer ที่ application ให้เล็กกว่า datagram ข้อมูลส่วนเกินอาจถูกตัดทิ้งตาม API และไม่สามารถเรียกอ่าน “ส่วนที่เหลือ” เหมือน stream ได้โดยอัตโนมัติ
Datagram ขนาดใหญ่ยังอาจนำไปสู่ IP fragmentation หรือไม่เหมาะกับ path MTU ซึ่งเพิ่มความเสี่ยงต่อ loss Application protocol จึงควรเลือกขนาด message และกลไกแบ่งข้อมูลอย่างระมัดระวัง ไม่ใช่เพียงเห็นว่า UDP รับได้หนึ่ง message แล้วส่งก้อนใหญ่เท่าไรก็ได้
5จาก Socket เดียว ไปสู่ Server ที่รับหลาย Client
Sequential Server เข้าใจง่าย แต่ Client คนเดียวอาจขวางทุกคน
Server แบบง่ายอาจ accept client หนึ่งราย รับ request ประมวลผล ส่ง response แล้วจึงกลับไปรับรายต่อไป หาก client แรกส่งข้อมูลช้า หรือเชื่อมแล้วไม่ส่งอะไร client อื่นทั้งหมดต้องรอ แม้ CPU และ network ยังว่างอยู่
Thread, Process, Event Loop และ Async I/O
| รูปแบบ | แนวคิด | ข้อดี | สิ่งที่ซับซ้อนขึ้น |
|---|---|---|---|
| Process per connection | แยก address space สำหรับแต่ละงาน | Isolation ดีและ model ตรงไปตรงมา | ต้นทุน process และการสื่อสารระหว่าง process |
| Thread per connection | แต่ละ connection มี thread รอและทำงาน | เขียนแบบลำดับได้ง่าย | จำนวน thread, synchronization และ shared state |
| Event loop | thread จำนวนน้อยเฝ้าหลาย socket แล้วทำงานเมื่อพร้อม | รองรับ connection จำนวนมากที่รอ I/O | ต้องจัด state machine และห้ามงานหนึ่ง block loop นาน |
| Async/Await | เขียน flow คล้ายลำดับแต่พักงานระหว่างรอ I/O | อ่านง่ายกว่า callback ในหลายกรณี | Cancellation, timeout, backpressure และ error propagation |
Concurrency ไม่ได้ทำให้ CPU เร็วขึ้นเอง แต่มันเปิดให้ server ใช้เวลาที่งานหนึ่งกำลังรอ I/O ไปดูแลงานอื่น การเลือก model ต้องดูจำนวน connection ระยะเวลารอ ปริมาณ CPU ต่อ request และความง่ายในการรักษา state ให้ถูกต้อง
Backpressure: เมื่อปลายทางช้ากว่า เราจะทำอย่างไร
หาก server สร้าง response เร็วกว่าที่ client รับได้ send buffer จะค่อย ๆ เต็ม ระบบต้องชะลอ producer, เก็บคิวเพิ่ม จำกัดปริมาณงาน หรือยกเลิก connection บางส่วน หากรับทุกอย่างโดยไม่มีขอบเขต หน่วยความจำจะกลายเป็น buffer สุดท้ายและล่มทั้ง process
Backpressure คือการส่งสัญญาณย้อนกลับว่าฝั่งถัดไปรับงานไม่ทัน แนวคิดนี้ปรากฏตั้งแต่ TCP flow control ไปจนถึง message queue และ microservices Socket programming ทำให้เราเห็นปัญหานี้ในรูปพื้นฐานที่สุด
6ข้อผิดพลาดที่ควรตรวจให้พบตั้งแต่ห้องปฏิบัติการ
| ความเข้าใจผิด | สิ่งที่เกิดขึ้นจริง | แนวทางตรวจหรือแก้ |
|---|---|---|
| หนึ่ง send ตรงกับหนึ่ง recv | TCP เป็น byte stream และแบ่ง/รวมข้อมูลได้ | ออกแบบ framing และวนอ่านจน message ครบ |
| send สำเร็จแปลว่าปลายทางทำงานแล้ว | อาจเพียงเขียนเข้า local buffer | ออกแบบ application acknowledgment หรือ response |
| recv ครั้งเดียวได้ข้อมูลครบ | อาจได้เพียงบางส่วน หรือถูก interrupt | วนอ่านและจัดการ partial read |
| timeout แปลว่า server ล้มเหลว | สถานะปลายทางยังคลุมเครือ | ใช้ request ID, idempotency และตรวจผลย้อนหลัง |
| listen backlog คือจำนวน client สูงสุด | เกี่ยวกับคิว connection ที่รอ ไม่ใช่ capacity ทั้งหมด | วัด accept rate, active connections และ processing capacity แยกกัน |
| UDP ไม่ต้องออกแบบ protocol | Application ยังต้องกำหนด message, timeout, retry และ security ตามงาน | เขียน wire format และ failure behavior ให้ชัด |
| close แล้วข้อมูลถึงครบแน่นอน | ผลขึ้นกับข้อมูลค้าง error และพฤติกรรมการปิด | ตรวจ return code และใช้ application-level completion เมื่อจำเป็น |
ตรวจ Return Value และ Error ทุกครั้ง
System call อาจล้มเหลว ถูก interrupt หรือทำงานได้เพียงบางส่วน โปรแกรมที่ทดสอบบนเครื่องเดียวอาจดูปกติ แต่พังเมื่อเจอ network delay, client disconnect หรือ resource limit การตรวจ return value ไม่ใช่งานตกแต่งหลังเขียนเสร็จ แต่เป็นส่วนหนึ่งของ semantics ของ API
นอกจาก error จาก network ยังมีข้อจำกัดของระบบ เช่น descriptor หมด memory ไม่พอ address ถูกใช้อยู่ หรือ permission ไม่เหมาะสม Network program จึงล้มเหลวได้แม้สาย network ไม่ได้มีปัญหาเลย
7สรุปบทนำร่วมและขั้นตอนถัดไป
- เครือข่ายต้องรองรับ application หลากหลาย พร้อมสมดุลมุมมองของ programmer, designer, provider และผู้ใช้จริง
- Connectivity ไม่ได้หมายถึงเพียงมีสายถึงกัน แต่รวมถึง topology, switching, addressing, routing และเส้นทางสำรอง
- Packet switching และ statistical multiplexing ช่วยแชร์ทรัพยากรตามการใช้งานจริง แต่ต้องรับมือ queue, congestion และความหน่วงที่เปลี่ยนแปลง
- Reliability มีหลายด้าน ได้แก่ integrity, delivery, duplication, ordering และ timeliness ไม่ใช่เพียง “ส่งถึงหรือไม่”
- Protocol กำหนด syntax, semantics และ timing ส่วน layering แบ่งหน้าที่และซ่อนรายละเอียดเท่าที่จำเป็น โดยระบบจริงอาจมี cross-layer interaction
- OSI เป็น reference model สำหรับแยกหน้าที่ ส่วน TCP/IP สะท้อนสถาปัตยกรรมและ protocol suite ที่ Internet ใช้งานจริง
- Performance ต้องแยก bandwidth, latency, throughput, goodput, RTT, jitter และ loss พร้อมระบุขอบเขตการวัด
- Socket API ทำให้ process เรียกใช้บริการสื่อสารได้ แต่ผลสำเร็จของ system call ไม่ควรถูกตีความเกินขอบเขตไปเป็นความสำเร็จของ application
send() แต่เส้นทางระหว่างสองจุดนี้ทำให้เห็นว่า “ส่งข้อมูล” ไม่ใช่ operation เดียว มันเป็นข้อตกลงหลายระดับ ตั้งแต่ signal, frame, packet, transport ไปจนถึงความหมายของ application Socket ทำให้รายละเอียดจำนวนมากใช้งานง่ายขึ้น แต่ไม่ได้ทำให้ความไม่แน่นอนเหล่านั้นหายไป
จากบทนำ ไปสู่การลงมือสร้าง Network Application
หลังจากนี้ผู้เรียนควรได้ทดลองเขียน TCP client/server ที่รองรับ partial read, framing และ timeout จากนั้นจึงเปรียบเทียบกับ UDP ทดลองจำลอง delay, disconnect และ message ซ้ำ เพื่อให้เห็นว่าแนวคิดในบท Reliability และ Performance ปรากฏใน code อย่างไร
เมื่อผ่านจุดนี้ Socket API จะไม่ใช่เพียงรายชื่อ function แต่เป็นรอยต่อที่ทุกแนวคิดก่อนหน้ามาพบกัน: address จาก Network Layer, port และ stream จาก Transport Layer, protocol จาก Application Layer และ failure ที่อาจเกิดได้ตลอดเส้นทาง
ขั้นตอนถัดไป — เลือกเส้นทางที่เหมาะกับจุดเริ่มต้น
ทุกเส้นทางศึกษาระบบเครือข่ายชุดเดียวกัน แต่เริ่มจากคนละมุมและใช้ระดับรายละเอียดต่างกัน สามารถเริ่มจากเส้นทางที่ใกล้พื้นฐานของตน แล้วกลับมาเติมมุมอื่นภายหลังได้