ทำความเข้าใจ INADDR_ANY สำหรับการเขียนโปรแกรมซ็อกเก็ต

ฉันกำลังพยายามตั้งโปรแกรมซ็อกเก็ตบางตัว และบนฝั่งเซิร์ฟเวอร์ ฉันใช้ htonl(INADDR_ANY) เท่าที่ฉันเข้าใจ สำหรับฉันแล้วดูเหมือนว่าฟังก์ชันนี้จะสร้าง IP แบบสุ่ม (ฉันถูกต้องหรือไม่) จริงๆ แล้ว ฉันต้องการผูกซ็อกเก็ตกับ localhost ของฉัน แต่ถ้าผมดำเนินการนี้

printf("%d",htonl(INADDR_ANY));

ฉันได้รับ 0 เป็นค่าส่งคืน ใครก็ได้ช่วยอธิบายหน่อยได้ไหม?


person epsilones    schedule 12.05.2013    source แหล่งที่มา
comment
... ฉันใช้ htonl(INADDR_ANY) เอกสารแจ้งว่าฟังก์ชันนี้สร้าง IP แบบสุ่ม ... ซึ่งไม่ถูกต้อง เอกสารใดที่บอกคุณเช่นนั้น?   -  person alk    schedule 12.05.2013
comment
@alk อันที่จริงฉันทำให้เข้าใจผิด: ฉันกำลังอ่าน pdf ฉันคิดว่าเป็นเอกสารอย่างเป็นทางการ ฉันแก้ไขโพสต์ของฉันตอนนี้   -  person epsilones    schedule 13.05.2013


คำตอบ (6)


  1. bind() จาก INADDR_ANY ไม่ "สร้าง IP แบบสุ่ม" เชื่อมโยงซ็อกเก็ตเข้ากับอินเทอร์เฟซที่มีอยู่ทั้งหมด

  2. สำหรับเซิร์ฟเวอร์ โดยทั่วไปคุณต้องการผูกเข้ากับอินเทอร์เฟซทั้งหมด ไม่ใช่แค่ "localhost"

  3. หากคุณต้องการผูกซ็อกเก็ตของคุณกับ localhost เท่านั้น ไวยากรณ์จะเป็น my_sockaddress.sin_addr.s_addr = inet_addr("127.0.0.1"); จากนั้นให้เรียก bind(my_socket, (SOCKADDR *) &my_sockaddr, ...)

  4. เมื่อมันเกิดขึ้น INADDR_ANY คือค่าคงที่ที่เกิดขึ้นเท่ากับ "ศูนย์":

    http://www.castaglia.org/proftpd/doc/devel-guide/src/include/inet.h.html

    # define INADDR_ANY ((unsigned long int) 0x00000000)
    ...
    # define INADDR_NONE    0xffffffff
    ...
    # define INPORT_ANY 0
    ...
    
  5. หากคุณไม่คุ้นเคย ฉันขอแนะนำให้คุณลองดูคู่มือการเขียนโปรแกรมซ็อกเก็ตของ Beej:

    http://beej.us/guide/bgnet/

เนื่องจากผู้คนยังคงอ่านข้อความนี้อยู่ หมายเหตุเพิ่มเติม:

ผู้ชาย (7) ไอพี:

เมื่อกระบวนการต้องการรับแพ็กเก็ตหรือการเชื่อมต่อขาเข้าใหม่ กระบวนการควรผูกซ็อกเก็ตกับที่อยู่อินเทอร์เฟซภายในเครื่องโดยใช้ ผูก(2).

ในกรณีนี้ ซ็อกเก็ต IP เดียวเท่านั้นที่สามารถผูกกับคู่ท้องถิ่น (ที่อยู่ พอร์ต) ที่กำหนดได้ เมื่อมีการระบุ INADDR_ANY ในการเรียกการผูก ซ็อกเก็ตจะถูกผูกไว้กับอินเทอร์เฟซภายในเครื่องทั้งหมด

เมื่อ listen(2) ถูกเรียกบนซ็อกเก็ตที่ไม่ถูกผูกไว้ ซ็อกเก็ตถูกผูกไว้กับพอร์ตว่างแบบสุ่มโดยอัตโนมัติโดยตั้งค่าที่อยู่ในเครื่องเป็น INADDR_ANY

เมื่อ connect(2) ถูกเรียกบนซ็อกเก็ตที่ไม่ถูกผูกไว้ ซ็อกเก็ตถูกผูกไว้กับพอร์ตว่างแบบสุ่มหรือพอร์ตที่ใช้ร่วมกันที่ใช้งานได้โดยอัตโนมัติโดยตั้งค่าที่อยู่ในเครื่องเป็น INADDR_ANY...

มีที่อยู่พิเศษหลายประการ: INADDR_LOOPBACK (127.0.0.1) อ้างถึงโฮสต์ภายในเครื่องผ่านอุปกรณ์ลูปแบ็คเสมอ INADDR_ANY (0.0.0.0) หมายถึง ที่อยู่ใดๆ สำหรับการผูกมัด...

อีกด้วย:

bind() — ผูก ชื่อซ็อกเก็ต:

หากฟิลด์ (sin_addr.s_addr) ถูกตั้งค่าเป็นค่าคงที่ INADDR_ANY ตามที่กำหนดไว้ใน netinet/in.h ผู้เรียกกำลังร้องขอให้เชื่อมต่อซ็อกเก็ตกับอินเทอร์เฟซเครือข่ายทั้งหมดบนโฮสต์ ต่อจากนั้น แพ็กเก็ต UDP และการเชื่อมต่อ TCP จากอินเทอร์เฟซทั้งหมด (ซึ่งตรงกับชื่อที่ผูกไว้) จะถูกส่งไปยังแอปพลิเคชัน สิ่งนี้มีความสำคัญเมื่อเซิร์ฟเวอร์เสนอบริการไปยังหลายเครือข่าย หากไม่ได้ระบุที่อยู่ เซิร์ฟเวอร์จะสามารถรับแพ็กเก็ต UDP และคำขอการเชื่อมต่อ TCP ทั้งหมดที่สร้างขึ้นสำหรับพอร์ตได้ โดยไม่คำนึงถึงอินเทอร์เฟซเครือข่ายที่คำขอมาถึง

person paulsm4    schedule 12.05.2013
comment
ไม่ได้หมายความว่า 'เชื่อมโยงกับอินเทอร์เฟซทั้งหมด' หากเป็นเช่นนั้น ผลลัพธ์ของ netstat จะแตกต่างออกไป หมายความว่า 'ฟังจากอินเทอร์เฟซ ใดก็ได้' - person user207421; 13.05.2013
comment
หากต้องการอ้างอิงลิงก์ด้านบน: เมื่อมีการระบุ INADDR_ANY ในการเรียกการเชื่อมโยง ซ็อกเก็ตจะถูกผูกไว้กับอินเทอร์เฟซภายในเครื่องทั้งหมด จากลิงก์อื่น: ค่า INADDR_ANY หมายความว่าเราจะผูกมัดกับที่อยู่ IP ใดๆ/ทั้งหมดที่ คอมพิวเตอร์ในระบบปัจจุบันมี แต่ใช่ - การใช้งานหลายอย่างจะเชื่อมโยงกับอินเทอร์เฟซ แรก (ไม่ใช่ทั้งหมด) แต่สำหรับพีซีเครื่องหนึ่งที่มี NIC หนึ่งเครื่อง ความแตกต่างคือเรื่องวิชาการ ด้วย INADDR_ANY ไคลเอ็นต์สามารถเชื่อมต่อกับ IP ใดๆ/ทั้งหมดได้ (เช่น ทั้ง 192.168.1.2 และ 127.0.0.1) - person paulsm4; 13.05.2013
comment
รับประกันว่าจะเท่ากับ 0 หรือไม่? - person 0x499602D2; 06.03.2015
comment
ขออภัยหากนี่เป็นคำถามงี่เง่า แต่อินเทอร์เฟซหมายถึงไร้สาย อีเธอร์เน็ต ฯลฯ หรือไม่ - person mrQWERTY; 18.03.2015
comment
เมื่อใดที่ผู้คนจะต้องผูกมัดกับ 127.0.0.1 แทนที่จะเป็น 0.0.0.0 - person laike9m; 15.09.2015
comment
@ laike9m คุณจะผูกกับ 127.0.0.1 เมื่อคุณต้องการเชื่อมต่อกับซ็อกเก็ตจากเครื่องท้องถิ่นเท่านั้น มีหลายกรณีการใช้งานเมื่อบริการที่นำเสนอโดยซ็อกเก็ตมีวัตถุประสงค์เพื่อใช้โดยกระบวนการอื่นที่อยู่ในเครื่องเท่านั้น - person dgnuff; 09.10.2015
comment
@dgnuff เหตุใดการเชื่อมโยงกับ 127.0.0.1 จึงป้องกันซ็อกเก็ตที่เชื่อมต่อจากเครื่องอื่น แม้ว่าฉันจะรู้ว่า 127.0.0.1 เป็นที่อยู่ในท้องถิ่น แต่ฉันไม่เข้าใจตรรกะหรือมีเอกสารนี้บันทึกไว้ที่ไหนสักแห่ง - person laike9m; 09.10.2015
comment
@ laike9m: ชื่ออื่นสำหรับที่อยู่นี้คืออินเทอร์เฟซแบบย้อนกลับ - เมื่อคุณส่ง มันจะวนกลับไปยังโฮสต์เดียวกันโดยไม่ต้องแตะต้องฮาร์ดแวร์เครือข่ายใด ๆ เลย รายละเอียดเพิ่มเติมมีดังนี้: อุปกรณ์ลูปแบ็คคืออะไร และฉันจะใช้มันอย่างไร - person paulsm4; 09.10.2015
comment
@ paulsm4 ใน 3 คุณไม่สามารถใช้ INADDR_LOOPBACK แทน inet_addr("127.0.0.1") ได้ไหม - person John Strood; 30.10.2016
comment
@ paulsm4 นอกจากนี้เมื่อคุณใช้ LOOPBACK สำหรับ sin_addr.s_addr ในแอปพลิเคชันเซิร์ฟเวอร์ หมายความว่าแอปพลิเคชันไคลเอนต์จากโฮสต์อื่นไม่สามารถเชื่อมต่อได้หรือไม่ - person John Strood; 30.10.2016

INADDR_ANY ถูกใช้เมื่อคุณไม่จำเป็นต้องผูกซ็อกเก็ตกับ IP ที่ระบุ เมื่อคุณใช้ค่านี้เป็นที่อยู่เมื่อโทร bind() ซ็อกเก็ตจะยอมรับการเชื่อมต่อกับ IP ทั้งหมดของเครื่อง

person Barmar    schedule 12.05.2013

หากต้องการ ผูก ซ็อกเก็ตกับ localhost ก่อนที่คุณจะเรียกใช้ฟังก์ชัน bind ฟิลด์ sin_addr.s_addr ของโครงสร้าง sockaddr_in ควรได้รับการตั้งค่าอย่างถูกต้อง จะได้ค่าที่เหมาะสมโดยวิธีใดวิธีหนึ่ง

my_sockaddress.sin_addr.s_addr = inet_addr("127.0.0.1")

or by

my_sockaddress.sin_addr.s_addr=htonl(INADDR_LOOPBACK);
person MichaelGoren    schedule 15.08.2013

INADDR_ANY สั่งให้ซ็อกเก็ตการฟังเชื่อมโยงกับอินเทอร์เฟซที่มีอยู่ทั้งหมด มันเหมือนกับการพยายามผูกกับ inet_addr("0.0.0.0") เพื่อความสมบูรณ์ ฉันจะกล่าวถึงด้วยว่ายังมี IN6ADDR_ANY_INIT สำหรับ IPv6 ด้วย และเหมือนกับการพยายามผูกกับที่อยู่ :: สำหรับซ็อกเก็ต IPv6

#include <netinet/in.h>

struct in6_addr addr = IN6ADDR_ANY_INIT;

นอกจากนี้ โปรดทราบว่าเมื่อคุณผูกซ็อกเก็ต IPv6 กับ IN6ADDR_ANY_INIT ซ็อกเก็ตของคุณจะผูกกับอินเทอร์เฟซ IPv6 ทั้งหมด และควรจะสามารถยอมรับการเชื่อมต่อจากไคลเอนต์ IPv4 ได้เช่นกัน (แม้ว่าที่อยู่ที่แมป IPv6)

person Pavel P    schedule 11.05.2018

INADDR_ANY เป็นค่าคงที่ที่มีค่า 0 สิ่งนี้จะใช้เฉพาะเมื่อคุณต้องการเชื่อมต่อจากพอร์ตที่ใช้งานอยู่ทั้งหมดที่คุณไม่สนใจ ip-add ดังนั้นหากคุณต้องการเชื่อมต่อ IP ใด ๆ คุณควรพูดถึงเช่น my_sockaddress.sin_addr.s_addr = inet_addr("192.168.78.2")

person vivek    schedule 12.07.2017

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

เมื่อคุณมีไคลเอ็นต์ คุณจะสร้างซ็อกเก็ต จากนั้นคุณเชื่อมต่อ() ซ็อกเก็ตกับ IP ระยะไกลและพอร์ต ซึ่งจะผูก 0.0.0.0 และพอร์ตชั่วคราวที่ไม่ได้ใช้แบบสุ่มเข้ากับซ็อกเก็ตหากยังไม่ได้ถูกผูกไว้แล้ว ไปยัง IP และพอร์ตโดยใช้การผูก (INADDR_ANY, 0) เชื่อมต่อ() ส่งคืนเมื่อเชื่อมต่อ และใช้ IP และพอร์ตเป็นที่อยู่ต้นทางในแพ็กเก็ตขาออก โดยที่ 0.0.0.0 จะถูกแทนที่ด้วย IP ภายในปัจจุบันโดยระบบปฏิบัติการเสมอ จากนั้นคุณใช้ sendall เพื่อส่งข้อมูลแอปพลิเคชัน

INADDR_ANY นั้นเร็วกว่าการรับ IP ภายในปัจจุบันของคอมพิวเตอร์โดยทางโปรแกรม ซึ่งอาจเปลี่ยนแปลงได้ตลอดเวลา และแพ็กเก็ตจะไม่ได้รับบนพอร์ตอีกต่อไป แต่จะยังคงได้รับบน 0.0.0.0 เนื่องจากเป็นที่อยู่ใดๆ

โปรดทราบว่าซ็อกเก็ตสามารถผูกกับ 0.0.0.0 ได้ แต่ไม่ใช่พอร์ต 0 เนื่องจากเป็นไวด์การ์ดที่ทำให้ซ็อกเก็ตมีพอร์ตชั่วคราวแบบสุ่ม ดังนั้นเมื่อคุณใช้การผูก (INADDR_ANY, 0) จะผูกกับ 0.0.0.0 และ พอร์ตชั่วคราวแบบสุ่ม

person Lewis Kelsey    schedule 08.06.2021