ฟังก์ชั่น socket API accept () ทำงานอย่างไร?


126

ซ็อกเก็ต API เป็นมาตรฐานโดยพฤตินัยสำหรับการสื่อสาร TCP / IP และ UDP / IP (นั่นคือรหัสเครือข่ายที่เรารู้จัก) อย่างไรก็ตามหนึ่งในฟังก์ชั่นหลักของมันaccept()นั้นมีมนต์ขลังเล็กน้อย

หากต้องการยืมคำจำกัดความกึ่งทางการ:

ยอมรับ () ถูกใช้ในฝั่งเซิร์ฟเวอร์ ยอมรับความพยายามที่เข้ามาเพื่อสร้างการเชื่อมต่อ TCP ใหม่จากไคลเอนต์ระยะไกลและสร้างซ็อกเก็ตใหม่ที่เชื่อมโยงกับคู่ที่อยู่ซ็อกเก็ตของการเชื่อมต่อนี้

กล่าวอีกนัยหนึ่งคือacceptส่งคืนซ็อกเก็ตใหม่ซึ่งเซิร์ฟเวอร์สามารถสื่อสารกับไคลเอ็นต์ที่เชื่อมต่อใหม่ได้ ซ็อกเก็ตเก่า (ซึ่งacceptถูกเรียกว่า) ยังคงเปิดอยู่บนพอร์ตเดียวกันเพื่อรับฟังการเชื่อมต่อใหม่

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

ฉันเดาว่ามันเป็นสิ่งที่อยู่ตามบรรทัดของที่อยู่ของลูกค้าที่เชื่อมโยงกับตัวอธิบายซ็อกเก็ตและเมื่อใดก็ตามที่ข้อมูลเข้ามาข้อมูลrecvจะถูกส่งไปยังซ็อกเก็ตที่ถูกต้อง แต่ฉันไม่แน่ใจ

เป็นการดีที่จะได้รับคำอธิบายอย่างละเอียดเกี่ยวกับการทำงานภายในของกลไกนี้


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

1
นี่เป็นคำถามพื้นฐานมากและฉันเพิ่งได้รับการทดสอบในเรื่องนี้ในการสัมภาษณ์: stackoverflow.com/questions/24871827/…หากคุณมีความคิดเห็นใด ๆ เกี่ยวกับเรื่องนี้โปรดโพสต์
พายุสมอง

@brainstorm เฉพาะในกรณีที่คุณเพิกเฉยต่อการมีอยู่ของ HTTP keep-alive
Marquis of Lorne

คำตอบ:


140

ความสับสนของคุณอยู่ที่การคิดว่าซ็อกเก็ตถูกระบุโดยเซิร์ฟเวอร์ IP: พอร์ตเซิร์ฟเวอร์ เมื่อตามความเป็นจริงซ็อกเก็ตจะถูกระบุโดยไม่ซ้ำกันโดยข้อมูลสี่ส่วน:

Client IP : Client Port และ Server IP : Server Port

ดังนั้นแม้ว่าเซิร์ฟเวอร์ IP และพอร์ตเซิร์ฟเวอร์จะคงที่ในการเชื่อมต่อที่ยอมรับทั้งหมดข้อมูลฝั่งไคลเอ็นต์คือสิ่งที่ช่วยให้สามารถติดตามได้ว่าทุกอย่างจะไปที่ใด

ตัวอย่างเพื่อชี้แจงสิ่งต่างๆ:

บอกว่าเรามีเซิร์ฟเวอร์ที่192.168.1.1:80สองลูกค้าและ10.0.0.110.0.0.2

10.0.0.1เปิดการเชื่อมต่อบนโลคัลพอร์ต1234และเชื่อมต่อกับเซิร์ฟเวอร์ ตอนนี้เซิร์ฟเวอร์มีซ็อกเก็ตเดียวที่ระบุดังนี้:

10.0.0.1:1234 - 192.168.1.1:80  

ตอนนี้10.0.0.2เปิดการเชื่อมต่อบนพอร์ตท้องถิ่น5678และเชื่อมต่อกับเซิร์ฟเวอร์ ตอนนี้เซิร์ฟเวอร์มีสองซ็อกเก็ตที่ระบุดังนี้:

10.0.0.1:1234 - 192.168.1.1:80  
10.0.0.2:5678 - 192.168.1.1:80

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

3
คุณมีข้อมูลอ้างอิงเกี่ยวกับเรื่องนี้หรือไม่?
qeek

3
คำถามสุ่ม: จะเกิดอะไรขึ้นหากใช้ NAT และไคลเอนต์สองตัวในเครือข่ายเดียวกันพยายามใช้พอร์ตโลคัลเดียวกันเมื่อเชื่อมต่อกับเซิร์ฟเวอร์ ตัวอย่างเช่นหากทั้ง 10.0.0.1 และ 10.0.0.2 เชื่อมต่อกับเราเตอร์ที่มี IP ภายนอก 192.168.0.1 ดังนั้นเซิร์ฟเวอร์ที่ 192.168.1.1 จะเห็นการเชื่อมต่อสองรายการจาก 192.168.0.1 จะเกิดอะไรขึ้นในกรณีนั้นถ้าเกิดจากความบังเอิญของตัวสร้างตัวเลขสุ่มทั้ง 10.0.0.1 และ 10.0.0.2 เลือกพอร์ตท้องถิ่นเดียวกัน
aroth

4
การสนับสนุน NAT ในเราเตอร์จะดูแลรายละเอียดที่นั่น การรับส่งข้อมูลเครือข่ายเกิดขึ้นมากกว่าสองการเชื่อมต่อ - ไคลเอนต์ไปยังเราเตอร์และเราเตอร์ไปยังเซิร์ฟเวอร์ เราเตอร์ทำการเชื่อมต่อขาออกบนพอร์ตที่แตกต่างกันสองพอร์ต 192.168.0.1:1234 และ 192.168.0.1:5678 จากนั้นการรับส่งข้อมูลขาเข้าจะถูกเปลี่ยนเส้นทางโดยเราเตอร์ไปยังไคลเอนต์ที่ถูกต้อง
17 จาก 26

3
ถ้าซ็อกเก็ตถูกระบุโดยควอเตตข้อมูลควอเตตของซ็อกเก็ตการฟังคืออะไร?
Eric Zheng

74

เพียงเพื่อเพิ่มคำตอบที่ได้รับจากผู้ใช้ "17 จาก 26"

ซ็อกเก็ตประกอบด้วย 5 ทูเปิล - (ip ต้นทาง, พอร์ตต้นทาง, ip ปลายทาง, พอร์ตปลายทาง, โปรโตคอล) ที่นี่โปรโตคอลสามารถ TCP หรือ UDP หรือโปรโตคอลชั้นการขนส่งใด ๆ โปรโตคอลนี้ถูกระบุในแพ็กเก็ตจากฟิลด์ 'โปรโตคอล' ใน IP datagram

ดังนั้นจึงเป็นไปได้ที่จะต้องใช้แอพพลิเคชั่นที่แตกต่างกันบนเซิร์ฟเวอร์ที่สื่อสารกับไคลเอนต์เดียวกันบน 4 tuples เดียวกัน แต่แตกต่างกันในฟิลด์โปรโตคอล ตัวอย่างเช่น

Apache ที่ฝั่งเซิร์ฟเวอร์พูดบน (server1.com:880-client1:1234 บน TCP) และ World of Warcraft กำลังพูดคุยบน (server1.com:880-client1:1234 บน UDP)

ทั้งไคลเอนต์และเซิร์ฟเวอร์จะจัดการสิ่งนี้เป็นฟิลด์โปรโตคอลในแพ็กเก็ต IP ในทั้งสองกรณีจะแตกต่างกันแม้ว่าอีก 4 ฟิลด์จะเหมือนกันก็ตาม


13

สิ่งที่ทำให้ฉันสับสนเมื่อฉันเรียนรู้สิ่งนี้คือคำศัพท์socketและportแนะนำว่าเป็นสิ่งที่มีอยู่จริงในความเป็นจริงมันเป็นเพียงโครงสร้างข้อมูลที่เคอร์เนลใช้เพื่อสรุปรายละเอียดของระบบเครือข่าย

ด้วยเหตุนี้โครงสร้างข้อมูลจึงถูกนำไปใช้เพื่อให้สามารถแยกการเชื่อมต่อจากไคลเอนต์ต่างๆ สำหรับวิธีการใช้งานคำตอบคือ a.) ไม่สำคัญจุดประสงค์ของ sockets API คือการใช้งานไม่ควรมีความสำคัญหรือ b.) เพียงแค่ดู นอกเหนือจากหนังสือของ Stevens ที่แนะนำเป็นอย่างยิ่งที่ให้คำอธิบายโดยละเอียดเกี่ยวกับการนำไปใช้งานหนึ่งรายการให้ตรวจสอบแหล่งที่มาใน Linux หรือ Solaris หรือหนึ่งใน BSD


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

-1

ดังที่อีกคนกล่าวว่าซ็อกเก็ตถูกระบุโดยเฉพาะด้วย 4-tuple (Client IP, Client Port, Server IP, Server Port)

กระบวนการเซิร์ฟเวอร์ที่ทำงานบนเซิร์ฟเวอร์ IP จะดูแลฐานข้อมูล (หมายความว่าฉันไม่สนใจว่าจะใช้โครงสร้างข้อมูลตาราง / รายการ / แผนภูมิ / อาร์เรย์ / เวทมนตร์แบบใด) ของซ็อกเก็ตที่ใช้งานอยู่และรับฟังบนพอร์ตเซิร์ฟเวอร์ เมื่อได้รับข้อความ (ผ่านสแต็ก TCP / IP ของเซิร์ฟเวอร์) ระบบจะตรวจสอบ IP ไคลเอ็นต์และพอร์ตกับฐานข้อมูล หากพบไคลเอ็นต์ IP และพอร์ตไคลเอ็นต์ในรายการฐานข้อมูลข้อความจะถูกส่งต่อไปยังตัวจัดการที่มีอยู่มิฉะนั้นรายการฐานข้อมูลใหม่จะถูกสร้างขึ้นและตัวจัดการใหม่จะถูกสร้างขึ้นเพื่อจัดการกับซ็อกเก็ตนั้น

ในช่วงแรก ๆ ของ ARPAnet โปรโตคอลบางอย่าง (FTP สำหรับหนึ่ง) จะรับฟังพอร์ตที่ระบุสำหรับคำขอเชื่อมต่อและตอบกลับด้วยพอร์ตแฮนด์ออฟ การสื่อสารเพิ่มเติมสำหรับการเชื่อมต่อนั้นจะไปที่พอร์ตแฮนด์ออฟ สิ่งนี้ทำขึ้นเพื่อปรับปรุงประสิทธิภาพต่อแพ็คเก็ต: คอมพิวเตอร์มีลำดับความสำคัญช้าลงหลายลำดับในสมัยนั้น


คุณสามารถอธิบายรายละเอียดในส่วนของ 'พอร์ตแฮนด์ออฟ' ได้หรือไม่?
Eli Bendersky

1
นี่เป็นคำอธิบายของโปรโตคอล pre-TCP บางส่วนหรือทำให้เข้าใจง่ายเกินไป ไคลเอนต์ที่พยายามเชื่อมต่อกับซ็อกเก็ตการฟังจะส่งแพ็กเก็ตพิเศษเพื่อสร้างการเชื่อมต่อ (ชุดบิต SYN) มีความแตกต่างที่ชัดเจนระหว่างแพ็คเก็ตที่สร้างซ็อกเก็ตใหม่และหนึ่งโดยใช้ซ็อกเก็ตที่มีอยู่
John M

... ส่งแพ็กเก็ตพิเศษเพื่อสร้างการเชื่อมต่อ (ชุดบิต SYN) ซึ่ง (ตามที่ฉันเข้าใจ) ทำให้โพรโทคอลสแต็กมอบให้กับ 'ผู้ฟัง' (ถ้ามี) ซึ่งเป็นเหตุผลว่าทำไมจึงมีพอร์ตการฟังเพียงพอร์ตเดียวต่อการรวมแอดเดรส / พอร์ต / โปรโตคอล ฉันไม่แน่ใจว่าสิ่งนี้อยู่ในข้อกำหนดหรือเป็นเพียงหลักการใช้งานเท่านั้น
Peter Wone

1
ย่อหน้าที่สองอธิบายไม่ถูกต้องว่าเกิดอะไรขึ้นที่เลเยอร์ TCP หรือภายในกระบวนการเซิร์ฟเวอร์ กระบวนการของเซิร์ฟเวอร์ไม่จำเป็นต้องรักษาโครงสร้างข้อมูลของซ็อกเก็ตใด ๆ หรือตรวจสอบ IP ขาเข้า: คู่พอร์ตเทียบกับสิ่งใดก็ตาม นั่นคือสิ่งที่มีไว้สำหรับซ็อกเก็ต FTP ใช้พอร์ตแยกต่างหากสำหรับข้อมูลไม่ใช่สำหรับ 'การสื่อสารเพิ่มเติม' ทั้งหมดและหมวกที่ทำเพื่อลดความซับซ้อนของโปรโตคอลไม่ใช่เพื่อเหตุผลด้านประสิทธิภาพ การใช้พอร์ตใหม่ในขณะที่ไม่ได้ปรับปรุงประสิทธิภาพ แต่อย่างใด
Marquis of Lorne

"เก็บรักษาฐานข้อมูล (หมายความว่าฉันไม่สนใจว่าจะใช้โครงสร้างข้อมูลตาราง / รายการ / แผนภูมิ / อาร์เรย์ / เวทมนตร์แบบใด)" :) ฉันมักเรียกสิ่งนี้ว่า "ตาราง" (หรืออาจจะเป็น "กราฟ" หรือ "แผนผังการตัดสินใจ" ) "ฐานข้อมูล" แนะนำการใช้งานบางอย่างให้ฉัน
masterxilo
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.