แพ็กเก็ต TCP และ UDP สามารถแบ่งออกเป็นชิ้น ๆ ได้หรือไม่?


41

แพ็กเก็ต TCP มาถึงผู้รับเป็นชิ้น ๆ ได้หรือไม่?

ตัวอย่างเช่นถ้าฉันส่ง 20 ไบต์โดยใช้โปรโตคอล TCP ฉันมั่นใจได้ 100% ว่าฉันจะได้รับ 20 ไบต์แน่นอนในครั้งเดียวไม่ใช่ 10 ไบต์แล้วจะเพิ่มอีก 10 ไบต์หรือไม่

และคำถามเดียวกันสำหรับโปรโตคอล UDP
ฉันรู้ว่า UDP นั้นไม่น่าเชื่อถือและแพ็คเก็ตไม่สามารถเข้าถึงได้ทั้งหมดหรือมาถึงในลำดับที่ต่างกัน แต่แพ็คเก็ตเดียวล่ะ? ถ้ามันมาถึงฉันจะแน่ใจได้ไหมว่ามันเป็นแพ็คเก็ตที่สมบูรณ์ไม่ใช่ชิ้น?


7
จุดของการชี้แจง: มันเรียกว่าเซ็กเมนต์ TCP และดาตาแกรม UDP พวกเขาไม่ใช่แพ็กเก็ต TCP = เซกเมนต์, UDP = ดาตาแกรม, IP = แพ็คเก็ต, อีเธอร์เน็ต = เฟรม, ที่เลเยอร์อื่น ๆ ทั้งหมด (AFAIK) พวกเขาเพียงแค่เรียกว่า PDU's (หน่วยข้อมูลโปรโตคอล)
joeqwerty

คำตอบ:


33

แพ็กเก็ต TCP มาถึงผู้รับเป็นชิ้น ๆ ได้หรือไม่

ใช่. IP รองรับการแตกแฟรกเมนต์แม้ว่าโดยทั่วไปแล้ว TCP จะพยายามกำหนดพา ธ MTU และเก็บแพ็คเก็ตให้เล็กกว่านั้นเพื่อเหตุผลด้านประสิทธิภาพ การแตกแฟรกเมนต์เพิ่มอัตราการสูญเสียดาตาแกรมอย่างหายนะ หากพา ธ มีอัตราการสูญหายของแพ็คเก็ต 10% การแยกส่วนดาตาแกรมออกเป็นสองแพ็กเก็ตจะทำให้ดาต้าอัพสูญเสียอัตราเกือบ 20% (หากแพ็กเก็ตหายไปดาต้าแกรมจะหายไป)

คุณไม่ต้องกังวลเกี่ยวกับสิ่งนี้แม้ว่าและเลเยอร์ TCP ก็ไม่เหมือนกัน เลเยอร์ IP รวบรวมข้อมูลลงในดาตาแกรมทั้งหมดอีกครั้ง

เช่นถ้าฉันส่ง 20 ไบต์โดยใช้โปรโตคอล TCP ฉันมั่นใจได้ 100% ว่าฉันจะได้รับ 20 ไบต์ในครั้งเดียวไม่ใช่ 10 ไบต์แล้วจะเพิ่มอีก 10 ไบต์หรือไม่

ไม่ แต่นั่นไม่เกี่ยวข้องกับแพ็กเก็ต TCP เป็นพื้นฐานของโปรโตคอลสตรีมไบต์ที่ไม่รักษาขอบเขตข้อความของแอปพลิเคชัน

และคำถามเดียวกันสำหรับโปรโตคอล UDP ฉันรู้ว่า UDP นั้นไม่น่าเชื่อถือและแพ็คเก็ตไม่สามารถไปถึงได้เลยหรือมาถึงในลำดับที่ต่างกัน

เช่นเดียวกับ TCP แพ็คเก็ตเป็นแพ็คเก็ต ความแตกต่างคือ TCP มีความพยายามและจัดลำดับใหม่อยู่ในโปรโตคอลในขณะที่ UDP ไม่ทำเช่นนั้น

แต่ประมาณ 1 แพ็คล่ะ ถ้ามันมาถึงฉันจะแน่ใจได้ไหมว่ามันเป็นแพ็คเก็ตที่สมบูรณ์ไม่ใช่ชิ้น?

ไม่ แต่นั่นไม่ใช่ปัญหาของคุณ โพรโทคอล UDP จัดการการรวบรวมข้อมูลอีกครั้งเดตาแกรม นั่นเป็นส่วนหนึ่งของงาน (ตามความเป็นจริงโปรโตคอล IP ทำสิ่งนี้สำหรับโปรโตคอล UDP ดังนั้น UDP ทำเพียงแค่วางเลเยอร์บน IP) หากดาตาแกรมได้รับการแบ่งออกเป็นสองแพ็กเก็ตโปรโตคอล IP จะรวมกันอีกครั้งสำหรับโปรโตคอล UDP ดังนั้นคุณ จะเห็นข้อมูลที่สมบูรณ์


10
อาจจะมีมูลค่าชี้แจงบิตสุดท้ายสำหรับผู้อ่านสามเณร: คุณจะเห็นข้อมูลที่สมบูรณ์แบบ สำหรับดาต้าในคำถาม หากแพ็กเก็ตใด ๆ ที่แยกขาดหายดาต้าแกรมจะหายไปและเลเยอร์ UDP จะไม่มีทางรู้ได้ ตราบใดที่ได้รับแพ็กเก็ตทั้งหมดในดาต้าแกรมพวกมันจะรวมตัวกันที่เลเยอร์ IP แล้วส่งต่อไปยังเลเยอร์ UDP สิ่งนี้ไม่ได้ขัดขวางความเป็นไปได้ของ "ชิ้นข้อมูล" ที่ขาดหายไปในดาต้าสตรีม เพื่อไม่ให้เป็นคนอวดรู้ แต่เมื่อฉันเรียนรู้สิ่งนี้ฉันไม่ได้หาความแตกต่างระหว่างการแตกของ IP และการสูญเสีย UDP จนกระทั่งครั้งที่ 2 หรือครั้งที่ 3 ผ่านตำราเรียน
Justin Justin

20

คุณไม่สามารถแน่ใจได้ว่าพวกเขามาถึงร่างกายในเวลาเดียวกันจริงๆ ชั้น Data link ด้านล่าง TCP / UDP อาจแบ่งแพ็คเก็ตของคุณหากพวกเขาต้องการ โดยเฉพาะอย่างยิ่งถ้าคุณส่งข้อมูลผ่านอินเทอร์เน็ตหรือเครือข่ายใด ๆ ที่อยู่นอกการควบคุมของคุณมันยากที่จะคาดการณ์ได้

แต่ไม่ว่าข้อมูลจะมาถึงในหนึ่งแพ็คเก็ตหรือหลายแพ็คเก็ตที่รับ ระบบปฏิบัติการควรสรุปการรวมกลุ่มของแพ็กเก็ตเหล่านี้ดังนั้นสำหรับแอปพลิเคชันของคุณมันยังดูเหมือนว่าทุกอย่างมาถึงในครั้งเดียว ดังนั้นหากคุณไม่ได้เป็นแฮกเกอร์เคอร์เนลในกรณีส่วนใหญ่คุณไม่จำเป็นต้องกังวลว่าข้อมูลนี้จะถูกถ่ายโอนในหนึ่งหรือหลายแพ็คเก็ต

สำหรับ UDP ระบบปฏิบัติการจะทำสิ่งที่เป็นนามธรรมดังนั้นแอปพลิเคชันที่รับข้อมูลไม่จำเป็นต้องทราบว่ามีการส่งข้อมูลจำนวนกี่แพ็คเก็ต แต่ความแตกต่างกับ TCP คือไม่มีการรับประกันว่าข้อมูลจะมาถึงจริง เป็นไปได้ว่าข้อมูลจะถูกแบ่งออกเป็นหลาย ๆ แพ็คเก็ตและบางอันก็มาถึงและบางอันก็ไม่ทำเช่นนั้น สำหรับแอปพลิเคชันที่รับจะมีลักษณะเหมือนสตรีมข้อมูลอยู่ดีไม่ว่าจะสมบูรณ์หรือไม่ก็ตาม


ไดรเวอร์การ์ดเครือข่ายไม่ดูแลการรวบรวมซ้ำแพ็กเก็ตไม่ใช่เคอร์เนลหรือไม่
bluehallu

2
@ Halucynogenyc: เว้นแต่ว่าสิ่งต่าง ๆ จะมีการเปลี่ยนแปลงโปรโตคอลอินเทอร์เน็ตได้รับการออกแบบมาเพื่อให้สามารถแยกแพ็คเก็ตที่มีขนาดมากกว่า 576 ไบต์ได้ทุกจุดในการเดินทางของพวกเขา แต่ไม่ได้คาดหวังอะไรเลย ฉันคิดว่าความคิดคือการใช้แพ็คเก็ตขนาดใหญ่เป็นส่วนใหญ่ความพยายามที่จะลดค่าใช้จ่าย; เมื่อแพ็คเก็ตได้รับการแยกในบางจุดในการเดินทางของมันค่าใช้จ่ายได้เกิดขึ้นแล้วเพื่อรวมตัวกันอีกครั้งก่อนที่ผู้รับสุดท้ายจะไม่ช่วยอะไรและอาจเจ็บถ้ามันจะแบ่งอีกครั้ง
supercat

ฉันเชื่อว่าในขณะที่แพ็คเก็ตใด ๆ ที่มีขนาดเกิน 576 ไบต์อาจถูกแยกออก แต่แพ็คเก็ตที่มีขนาดต่ำกว่านั้นอาจไม่ได้ ระบบฝังตัวที่ไม่สามารถจัดการกับแพ็คเก็ตแยกควรหลีกเลี่ยงสิ่งที่ใหญ่กว่านั้น
supercat

1
@ mauro.stettler: ฉันได้เขียนสแต็ก TCP บน "bare metal" (การเขียนรหัสเพื่อพูดคุยโดยตรงกับชิปอินเตอร์เฟสเครือข่ายจำนวนมาก) สำหรับฮาร์ดแวร์ที่พูดถึงลิงก์ที่มีขีด จำกัด 576- ไบต์เพื่อแยกแพ็คเก็ตที่ยาวขึ้นนั้นเป็นเรื่องง่าย การรวบรวมซ้ำแพ็คเก็ตมีความซับซ้อนมากขึ้นโดยเฉพาะอย่างยิ่งเนื่องจากอาจได้รับชิ้นส่วนของแพ็คเก็ตที่แตกต่างกันจำนวนมากก่อนที่จะได้รับเต็ม
supercat

มีความหวังว่ามันจะไม่ถูกแยกสำหรับpayloads เล็ก ๆ (ประมาณ 10 หรือ 20 ไบต์ควรเป็น ok) เนื่องจากมี "ขนาดสูงสุดรับประกัน" ที่จำเป็นสำหรับการกระโดดแต่ละครั้งสำหรับ IP paquets บน ipv4: อย่างน้อย 68 ไบต์ (รวมถึง ส่วนหัว IP และไม่นับส่วนหัวระดับล่าง ดูตารางที่ 1 ในen.wikipedia.org/wiki/Maximum_transmission_unit แตกต่างจาก 576 ไบต์ที่มีขนาดเล็กที่สุดที่ต้องการจาก HOSTS (เช่นต้นทางหรือจุดสิ้นสุดของการส่งไม่ใช่ฮิพฮอพทั้งหมด) และระวัง: น้ำหนักบรรทุกยังคงต่ำกว่า (เนื่องจากส่วนหัวของแต่ละชั้นใช้พื้นที่)
Olivier Dulac

14

ตัวอย่าง. บล็อกของอักขระที่ต่อเนื่องกันสอดคล้องกับการเรียก send ():

TCP:

Send: AA BBBB CCC DDDDDD E         Recv: A ABB B BCC CDDD DDDE

ข้อมูลทั้งหมดที่ส่งได้รับตามลำดับ แต่ไม่จำเป็นต้องอยู่ในกลุ่มเดียวกัน

UDP:

Send: AA BBBB CCC DDDDDD E         Recv: CCC AA E

ข้อมูลไม่จำเป็นต้องอยู่ในลำดับเดียวกันและไม่จำเป็นต้องได้รับเลย แต่ข้อความจะได้รับการเก็บรักษาไว้อย่างครบถ้วน


5

เช่นถ้าฉันส่ง 20 ไบต์โดยใช้โปรโตคอล TCP ฉันจะแน่ใจได้ 100% ว่าฉันจะได้รับ 20 ไบต์แน่นอนในครั้งเดียวไม่ใช่ 10 ไบต์จากนั้นอีก 10 ไบต์หรือมากกว่านั้น

ไม่ TCP เป็นโปรโตคอลสตรีมมันเก็บข้อมูลตามลำดับ แต่จะไม่จัดกลุ่มตามข้อความ ในทางกลับกัน UDP เป็นข้อความ แต่ไม่น่าเชื่อถือ SCTPมีทั้งดีที่สุดในโลก แต่ไม่สามารถใช้งานได้จริงเนื่องจาก NATs ทำลายอินเทอร์เน็ต


1

มีความมั่นใจว่าถ้าคุณส่ง 20 ไบต์ที่จุดเริ่มต้นของสตรีม TCP มันจะไม่มาถึงสอง 10 ไบต์ นี่เป็นเพราะสแต็ก TCP จะไม่ส่งเซกเมนต์ขนาดเล็กดังกล่าว: มีขนาด MTU ขั้นต่ำ อย่างไรก็ตามหากการส่งอยู่ที่ใดก็ได้ในช่วงกลางของกระแสการเดิมพันทั้งหมดจะปิด อาจเป็นไปได้ว่าโปรโตคอลสแต็กของคุณใช้ข้อมูล 10 ไบต์ในการกรอกกลุ่มและส่งออกและจากนั้นสิบไบต์ถัดไปจะไปยังส่วนอื่น

โปรโตคอลสแต็กของคุณแบ่งข้อมูลออกเป็นชิ้น ๆ และวางลงในคิว ขนาดของก้อนขึ้นอยู่กับพา ธ MTU หากคุณดำเนินการส่งและยังคงมีข้อมูลที่ค้างอยู่รอโพรโทคอลสแต็คโดยทั่วไปจะมองไปที่เซ็กเมนต์ซึ่งอยู่ที่ส่วนท้ายของคิวและดูว่ามีที่ว่างในเซ็กเมนต์นั้นเพื่อเพิ่มข้อมูลเพิ่มเติมหรือไม่ ห้องอาจมีขนาดเล็กเท่ากับหนึ่งไบต์ดังนั้นแม้แต่การส่งแบบสองไบต์ก็อาจแบ่งเป็นสอง

ในอีกด้านหนึ่งการแบ่งส่วนของข้อมูลหมายความว่าสามารถอ่านได้บางส่วน การดำเนินการรับอาจปลุกและรับข้อมูลเมื่อมีน้อยถึงหนึ่งเซ็กเมนต์ที่มาถึง ใน sockets API ที่มีการใช้งานอย่างกว้างขวางการรับสายสามารถขอได้ 20 ไบต์ แต่สามารถส่งคืนได้ด้วย 10 แน่นอนว่าชั้นการบัฟเฟอร์สามารถสร้างขึ้นได้ซึ่งจะบล็อกจนกว่าจะได้รับ 20 ไบต์หรือการเชื่อมต่อหยุดชะงัก ในโลก POSIX, API นั้นสามารถเป็นสตรีม I / O มาตรฐาน: คุณสามารถfdopenใช้ socket descriptor เพื่อรับFILE *สตรีมและคุณสามารถใช้freadมันเพื่อเติมบัฟเฟอร์ซึ่งคำขอเต็มจะพอใจกับการreadเรียกจำนวนมากตามที่ใช้ .

UDP ดาตาแกรมเฟรมข้อมูล การโทรส่งแต่ละครั้งจะสร้างดาตาแกรม (แต่ดูด้านล่างเกี่ยวกับการเปิดคอร์ก) อีกด้านหนึ่งได้รับดาตาแกรมเต็มรูปแบบ (และในซ็อกเก็ต API นั้นจะต้องระบุบัฟเฟอร์ที่มีขนาดใหญ่พอที่จะเก็บไว้มิฉะนั้นเดตาแกรมจะถูกตัดทอน) ดาต้าแกรมขนาดใหญ่ได้รับการแยกส่วนโดยการแยกส่วน IP และประกอบเข้ากับแอปพลิเคชันใหม่อย่างโปร่งใส หากส่วนใดขาดหายไปดาตาแกรมทั้งหมดจะหายไป ไม่มีวิธีการอ่านข้อมูลบางส่วนในสถานการณ์นั้น

มีส่วนขยายไปยังส่วนต่อประสานที่อนุญาตการดำเนินการหลายอย่างเพื่อระบุดาตาแกรมเดียว ใน Linux ซ็อกเก็ตสามารถ "corked" (ป้องกันไม่ให้ส่ง) ในขณะที่มันถูกคอร์กข้อมูลที่เขียนจะถูกรวบรวมเป็นหน่วยเดียว จากนั้นเมื่อซ็อกเก็ต "ไม่ได้เปิด" สามารถส่งดาตาแกรมเดียวได้


นี่เป็นเท็จ: ถ้าใครส่ง paquet ที่มี 10 หรือ 20 bytes payload สิ่งนี้จะสร้าง 1 paquet และ (ดังที่ฉันได้กล่าวไว้ข้างต้น), ถ้าใช้ ipv4, มันควร, แม้ว่าจะเพิ่มส่วนหัวทั้งหมดของเลเยอร์โปรโตคอลอื่น ๆ เป็นภายใน 68 ไบต์จึงมั่นใจได้ว่าจะผ่านทุกฮ็อพใน 1 แพ็คเก็ต Tcp stack จะไม่ (ตามที่บอกไว้ในย่อหน้าที่ 1 ของคุณ) "รอจนกว่าจะมีการเติม mtu (กล่าวคือเพิ่มแพ็กเก็ตจำนวนมากเพื่อให้มีขนาดที่เหมาะสม)" เพื่อส่งแพ็คเก็ต! ... พฤติกรรมนี้จะทำลายหลายสิ่ง ( แม้ว่า "แฟรกเมนต์" เหล่านั้นถูกส่งจาก & ไปยังโฮสต์คู่เดียวกัน)
Olivier Dulac

@OlivierDulac: นั่นไม่ถูกต้อง TCP มักจะสร้างแพ็คเก็ตตามที่ต้องการพยายามเพิ่มประสิทธิภาพการใช้เครือข่ายดังนั้น 20 ไบต์จะสิ้นสุดในสองแพ็กเก็ตที่แตกต่างกันตามที่อธิบายโดย Kaz สิ่งนี้สามารถควบคุมได้โดยใช้ตัวเลือกซ็อกเก็ตTCP_NODELAYซึ่งปิดใช้งานอัลกอริทึม Nagles ที่ส่งไบต์ไปยังแพ็คเก็ตหากแอปพลิเคชันของคุณต้องการเครือข่าย TCP ที่เร็วขึ้น นอกจากนี้ 68 ไบต์ไม่ได้หมายความว่ามาตรฐาน de-facto สำหรับความยาวของแพ็คเก็ต: 1500 ไบต์เป็นค่าเริ่มต้นที่ปกติกว่าปกติ
jjmontes
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.