จับมือ TCP 3-way ทำงานเช่นนี้:
Client ------SYN-----> Server
Client <---ACK/SYN---- Server
Client ------ACK-----> Server
ทำไมไม่ทำอย่างนี้ล่ะ?
Client ------SYN-----> Server
Client <-----ACK------ Server
จับมือ TCP 3-way ทำงานเช่นนี้:
Client ------SYN-----> Server
Client <---ACK/SYN---- Server
Client ------ACK-----> Server
ทำไมไม่ทำอย่างนี้ล่ะ?
Client ------SYN-----> Server
Client <-----ACK------ Server
คำตอบ:
ทำลายการจับมือกันในสิ่งที่มันกำลังทำอยู่
ใน TCP ทั้งสองฝ่ายติดตามสิ่งที่พวกเขาส่งโดยใช้หมายเลขลำดับ อย่างมีประสิทธิภาพมันจบลงด้วยการนับไบต์ทำงานของทุกสิ่งที่ถูกส่ง ฝ่ายรับสามารถใช้หมายเลขลำดับของผู้พูดตรงกันข้ามเพื่อรับทราบสิ่งที่ได้รับ
แต่หมายเลขลำดับไม่เริ่มต้นที่ 0 มันเริ่มต้นที่ ISN (หมายเลขลำดับเริ่มต้น) ซึ่งเป็นค่าที่เลือกแบบสุ่ม และเนื่องจาก TCP เป็นการสื่อสารแบบสองทิศทางทั้งสองฝ่ายสามารถ "พูด" และดังนั้นทั้งสองจึงต้องสุ่มสร้าง ISN เป็นหมายเลขลำดับเริ่มต้นของพวกเขา ซึ่งในทางกลับกันทั้งสองฝ่ายจำเป็นต้องแจ้งให้อีกฝ่ายทราบถึง ISN เริ่มต้นของพวกเขา
ดังนั้นคุณจะจบลงด้วยลำดับเหตุการณ์สำหรับการเริ่มต้นการสนทนา TCP ระหว่าง Alice และ Bob:
Alice ---> Bob SYNchronize with my Initial Sequence Number of X
Alice <--- Bob I received your syn, I ACKnowledge that I am ready for [X+1]
Alice <--- Bob SYNchronize with my Initial Sequence Number of Y
Alice ---> Bob I received your syn, I ACKnowledge that I am ready for [Y+1]
สังเกตเห็นเหตุการณ์สี่เหตุการณ์กำลังเกิดขึ้น:
ในความเป็นจริงแม้ว่าเหตุการณ์กลางสอง (# 2 และ # 3) เกิดขึ้นในแพ็กเก็ตเดียวกัน สิ่งที่ทำให้แพ็กเก็ต a SYN
หรือACK
เป็นเพียงการเปิดหรือปิดแฟล็กไบนารีภายในแต่ละส่วนหัว TCPดังนั้นจึงไม่มีสิ่งใดที่จะป้องกันไม่ให้แฟล็กทั้งสองนี้เปิดใช้งานบนแพ็กเก็ตเดียวกัน ดังนั้นการจับมือสามทางจึงเป็น:
Bob <--- Alice SYN
Bob ---> Alice SYN ACK
Bob <--- Alice ACK
สังเกตเห็นสองอินสแตนซ์ของ "SYN" และ "ACK" ซึ่งเป็นหนึ่งในแต่ละอินสแตนซ์
ดังนั้นเพื่อกลับมาที่คำถามของคุณทำไมไม่ใช้มือจับสองทาง? คำตอบสั้น ๆ ก็คือเพราะการจับมือสองทางจะอนุญาตให้ฝ่ายหนึ่งสร้าง ISN เท่านั้นและอีกฝ่ายรับทราบ ซึ่งหมายความว่ามีเพียงฝ่ายเดียวเท่านั้นที่สามารถส่งข้อมูลได้
แต่ TCP เป็นโปรโตคอลการสื่อสารแบบสองทิศทางซึ่งหมายความว่าปลายทั้งสองควรจะสามารถส่งข้อมูลได้อย่างน่าเชื่อถือ ทั้งสองฝ่ายจำเป็นต้องสร้าง ISN และทั้งสองฝ่ายจำเป็นต้องยอมรับ ISN ของอีกฝ่าย
ดังนั้นในผลสิ่งที่คุณมีอยู่ตรงคำอธิบายของคุณของการจับมือกันสองทาง แต่ในแต่ละทิศทาง ดังนั้นสี่เหตุการณ์ที่เกิดขึ้น และอีกครั้งธงกลางสองเกิดขึ้นในแพ็กเก็ตเดียวกัน เช่นเดียวกับสามแพ็กเก็ตที่เกี่ยวข้องในกระบวนการเริ่มต้นการเชื่อมต่อ TCP แบบเต็ม
การจับมือสามทางเป็นสิ่งจำเป็นเพราะทั้งสองฝ่ายต้องsyn chronize หมายเลขลำดับส่วนที่ใช้ในระหว่างการส่งของพวกเขา สำหรับเรื่องนี้แต่ละของพวกเขาส่ง (ในทางกลับกัน) ส่วน SYN มีหมายเลขลำดับที่กำหนดเป็นค่าสุ่มnซึ่งจากนั้นจะแอ๊ nowledged โดยบุคคลอื่น ๆ ผ่านทางส่วน ACK ที่มีหมายเลขลำดับที่กำหนดไป1 + n
Eddie
ความคิดเห็นจากคำตอบของเขา
เพื่อให้การเชื่อมต่อใช้งานได้แต่ละด้านจำเป็นต้องตรวจสอบว่าสามารถส่งแพ็กเก็ตไปยังอีกด้านหนึ่งได้ วิธีเดียวที่จะให้แน่ใจว่าคุณได้รับแพ็คเก็ตไปด้านอื่น ๆ คือการได้รับแพ็คเก็ตจากพวกเขาว่าโดยความหมายจะไม่ได้รับการส่งเว้นแต่แพ็คเก็ตที่คุณส่งได้ผ่าน TCP เป็นหลักใช้สองชนิดของข้อความนี้: SYN (เพื่อขอหลักฐานว่าแพ็คเก็ตนี้ได้ผ่าน) และ ACK (ซึ่งได้รับการส่งไปหลังจากที่ได้รับผ่าน SYN เพื่อพิสูจน์ว่า SYN ได้ผ่าน) จริง ๆ แล้วมีข้อความประเภทที่สาม แต่เราจะไปถึงในเวลาไม่นาน
ก่อนที่จะเริ่มการเชื่อมต่อไม่มีฝ่ายใดรู้อะไรเกี่ยวกับอีกฝ่าย ไคลเอนต์ส่งแพ็คเก็ต SYN ไปยังเซิร์ฟเวอร์เพื่อขอการพิสูจน์ว่าข้อความสามารถผ่านได้ นั่นไม่ได้บอกอะไรกับใครเลย แต่เป็นขั้นตอนแรกของการจับมือกัน
ถ้า SYN ผ่านมาเซิร์ฟเวอร์จะรู้ว่าไคลเอ็นต์สามารถส่งแพ็กเก็ตไปได้เพราะมันเพิ่งเกิดขึ้น แต่นั่นไม่ได้พิสูจน์ว่าเซิร์ฟเวอร์สามารถส่งแพ็กเก็ตกลับ: ลูกค้าสามารถส่ง SYNs สำหรับจำนวนของเหตุผล ดังนั้นเซิร์ฟเวอร์จำเป็นต้องส่งข้อความสองข้อความกลับไปยังไคลเอนต์: ACK (เพื่อพิสูจน์ว่า SYN ได้ผ่าน) และ SYN (เพื่อร้องขอ ACK ของตนเอง) TCP จะรวมข้อความทั้งสองนี้ไว้ในข้อความ -a SYN-ACK หนึ่งข้อความหากคุณต้องการลดทราฟฟิกเครือข่าย นี่เป็นขั้นตอนที่สองของการจับมือกัน
เนื่องจาก SYN-ACK เป็น ACK ตอนนี้ไคลเอนต์ทราบดีว่าสามารถส่งแพ็กเก็ตไปยังเซิร์ฟเวอร์ได้ และเนื่องจาก SYN-ACK เป็น SYN จึงรู้ว่าเซิร์ฟเวอร์ต้องการพิสูจน์ว่าข้อความนี้ผ่าน ดังนั้นมันจึงส่ง ACK กลับมา: เพียงแค่ ACK ธรรมดาในครั้งนี้เพราะมันไม่จำเป็นต้องมีการพิสูจน์อีกต่อไปว่าแพ็กเก็ตของมันจะผ่านได้ นี้เป็นขั้นตอนสุดท้ายของการจับมือกัน: ลูกค้าตอนนี้รู้ว่าแพ็คเก็ตสามารถไปทั้งสองวิธีและที่เซิร์ฟเวอร์เป็นเพียงเกี่ยวกับการที่จะคิดออกนี้ (เพราะมันรู้ ACK จะผ่านไป)
เมื่อ ACK ผ่านไปแล้วตอนนี้เซิร์ฟเวอร์รู้ว่าสามารถส่งแพ็กเก็ตไปยังไคลเอนต์ได้ นอกจากนี้ยังรู้ว่าลูกค้ารู้สิ่งนี้ดังนั้นจึงสามารถเริ่มส่งข้อมูลได้ทันที การจับมือกันเสร็จสมบูรณ์ เรามีช่องทางที่ดี
ดีอย่างเคร่งครัดพูดเราไม่สามารถเป็นบางอย่างที่เรามีช่องทางที่ดี เพียงเพราะลำดับของแพ็คเก็ตที่ผ่านไปนี้ไม่ได้รับประกันอย่างเคร่งครัดว่าคนอื่นจะ เราไม่สามารถพิสูจน์ได้ว่าหากไม่มีการส่ง SYN และ ACK จำนวนอนันต์แล้วไม่มีสิ่งอื่นใดที่จะเสร็จสิ้นดังนั้นจึงไม่ใช่ตัวเลือกที่ใช้งานได้จริง แต่ในทางปฏิบัติสามขั้นตอนจะเปิดออกจะดีพอสำหรับวัตถุประสงค์มากที่สุด
ที่จริงแล้วการจับมือ 3 ทางไม่ใช่วิธีเดียวในการสร้างการเชื่อมต่อ TCP อนุญาตให้มีการแลกเปลี่ยน SYN พร้อมกัน: http://www.tcpipguide.com/free/t_TCPConnectionEstablishmentProcessTheThreeWayHandsh-4.htm
ซึ่งอาจถูกมองว่าเป็นการจับมือแบบสองทางสองทาง
การเชื่อมต่อ TCP เป็นแบบสองทิศทาง สิ่งนี้หมายความว่าจริงๆแล้วมันคือการเชื่อมต่อแบบทางเดียว ผู้ริเริ่มส่ง SYN ผู้ตอบกลับจะส่ง ACK: การเชื่อมต่ออย่างง่าย ๆ เริ่มต้นขึ้น "จากนั้น" ผู้ตอบกลับจะส่ง SYN ผู้ริเริ่มส่ง ACK: เริ่มการเชื่อมต่ออย่างง่ายอีกครั้ง การเชื่อมต่อ simplex สองรูปแบบสร้างหนึ่งช่วง TCP สองเพล็กซ์เห็นด้วยไหม ดังนั้นเหตุผลมีสี่ขั้นตอนที่เกี่ยวข้อง แต่เนื่องจากแฟล็ก SYN และ ACK เป็น "ฟิลด์" ที่แตกต่างกันของส่วนหัว TCP พวกเขาสามารถตั้งค่าพร้อมกัน - ขั้นตอนที่สองและสาม (ของสี่) รวมกันดังนั้นในทางเทคนิคแล้วมีการแลกเปลี่ยนแพ็คเก็ตสามครั้ง การเชื่อมต่อ simplex (half-) แต่ละอันใช้การแลกเปลี่ยน 2 ทางตามที่คุณเสนอ
หากเซิร์ฟเวอร์และลูกค้าต้องการสร้างการเชื่อมต่อพวกเขาต้องการการยืนยันสี่สิ่ง:
ลูกค้าจำเป็นต้องยืนยันว่าเขาสามารถรับแพ็คเก็ตจากเซิร์ฟเวอร์
ลูกค้าจำเป็นต้องยืนยันสิ่ง: เซิร์ฟเวอร์สามารถรับแพ็คเก็ตจากลูกค้า
หลังจากClient ------SYN-----> Server
กฎ 1 ได้รับการยืนยันแล้ว
หลังจากClient <---ACK/SYN---- Server
กฎ 2 และ 3 ได้รับการยืนยันแล้ว
ดังนั้นต้องมีแพ็กเก็ตที่สามเพื่อยืนยันกฎ 4
ไม่จำเป็นเลย เห็นได้ชัดว่าข้อความสั้น ๆ ควรเพียงหนึ่งแพ็คเก็ตไปยังเซิร์ฟเวอร์ซึ่งรวมถึงการเริ่มต้น + ข้อความและหนึ่งแพ็คเก็ตกลับยอมรับมัน
คำตอบก่อนหน้านี้เพียงแค่อธิบายระบบโดยไม่ต้องพูดถึงความต้องการหมายเลขลำดับแบบสุ่ม ฯลฯ ในตอนแรก คำถามดั้งเดิมเกี่ยวกับการออกแบบ TCP นั้นแน่นอนว่าถ้าคุณใช้โปรโตคอล TCP คุณต้องมีสามข้อความเพราะนั่นคือโปรโตคอล แต่ทำไม TCP ถึงได้รับการออกแบบมาตั้งแต่แรก?
ฉันเชื่อว่าความคิดดั้งเดิมคือว่าไม่มีความแตกต่างระหว่างลูกค้าและเซิร์ฟเวอร์ ทั้งคู่รู้จักพอร์ตของอีกฝ่ายในลักษณะสองทิศทางและสามารถเริ่มการสนทนาได้ และนั่นคือสิ่งที่จำเป็น Syns ฯลฯ
แต่นี่ไม่ใช่แน่นอนว่ามันถูกใช้ในปัจจุบันอย่างไร เซิร์ฟเวอร์ฟังพอร์ตที่รู้จักกันดีและทำและ "ยอมรับ" หมายเลขพอร์ตไคลเอ็นต์คือชั่วคราว ฉันไม่คิดว่ามันจะเป็นไปได้สำหรับเซิร์ฟเวอร์ที่รอ "ยอมรับ" เพื่อส่งคำขอไปยังหมายเลขพอร์ตลูกค้าเดียวกันในระบบปฏิบัติการปกติ
(โปรดทราบว่านี่เป็นเรื่องเกี่ยวกับการเริ่มต้นการเชื่อมต่อแบบสองทิศทางซึ่งไม่เคยทำในวันนี้ซึ่งค่อนข้างแตกต่างจากการส่งข้อความแบบสองทิศทางในการเชื่อมต่อที่สร้างขึ้นครั้งเดียว)
เพื่อหลีกเลี่ยง TCP ที่ไม่มีประสิทธิภาพเราใช้โปรโตคอลเช่น HTTP 1.1 ซึ่งสามารถนำการเชื่อมต่อเดียวกันมาใช้ซ้ำสำหรับการร้องขอหลายครั้งและหลีกเลี่ยงการจับมือ TCP ซึ่งไม่จำเป็นในตอนแรก
แต่ Http 1.1 นั้นค่อนข้างใหม่ และ SSL / TLS ต้องการวิธีที่จะนำเซสชันมาใช้ใหม่ตั้งแต่ต้นเนื่องจากค่าใช้จ่ายของอัลกอริทึม PKI ดังนั้นโปรโตคอลจึงรวมถึงกลไกการใช้งานซ้ำซึ่งทำงานบน Http 1.1 ซึ่งทำงานบน TCP
นั่นเป็นวิธีที่มีซอฟต์แวร์ ฟัดจ์ที่กากตะกอนซึ่งเมื่อรวมเข้าด้วยกันจะให้ผลลัพธ์ที่ยอมรับได้
หลังจากอ่านคำตอบของ Eddie (ยอมรับว่าถูกต้อง) ยังมีคำถามว่าทำไมโฮสต์ที่ 1 ไม่สามารถกำหนดทั้งสองของ ISN ด้วยตัวเลขสุ่มและอันดับที่ 2 ก็ยอมรับได้ เหตุผลที่แท้จริงของการใช้ 3 วิธีการจับมือกันคือการหลีกเลี่ยงครึ่งเชื่อมต่อ สถานการณ์การเชื่อมต่อครึ่งทางในการจับมือ 2 ทาง:
1) ไคลเอนต์ --- SYN -> เซิร์ฟเวอร์
2) ไคลเอ็นต์เปลี่ยนใจและไม่ต้องการเชื่อมต่ออีกต่อไป
3) ไคลเอ็นต์ <-X-ACK-- เซิร์ฟเวอร์ // ACK หายไป
เซิร์ฟเวอร์ไม่เห็น SYN ส่งอีกครั้งดังนั้นเขาจึงคิดว่าไคลเอ็นต์ได้รับ ACK ของเขาและการเชื่อมต่อได้รับการจัดตั้งขึ้น เป็นผลให้เซิร์ฟเวอร์มีการเชื่อมต่อที่จะไม่ถูกปิด