Hiểu INADDR_ANY để lập trình socket


84

Tôi đang cố gắng lập trình một số ổ cắm và vì vậy, ở phía máy chủ, tôi sử dụng htonl(INADDR_ANY). Trong phạm vi tôi hiểu, có vẻ như đối với tôi chức năng này tạo ra một IP ngẫu nhiên (tôi có đúng không?). Trong thực tế, tôi muốn liên kết ổ cắm của tôi với của tôi localhost. Nhưng nếu tôi chạy cái này

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

Tôi nhận được 0 như một giá trị trả về. Ai đó có thể mang lại một số lời giải thích?


9
" ... Tôi sử dụng htonl(INADDR_ANY). Tài liệu nói rằng hàm này tạo ra một IP ngẫu nhiên ... " Điều này không chính xác. Tài liệu nào nói với bạn như vậy?
alk

1
@alk, thực tế là tôi đã đánh lừa: Tôi đang đọc một số bản pdf mà tôi nghĩ là một số tài liệu chính thức. Tôi chỉnh sửa bài đăng của mình ngay bây giờ
epsilones

Câu trả lời:


132
  1. bind()của INADDR_ANYkhông KHÔNG "tạo một IP ngẫu nhiên". Nó liên kết ổ cắm với tất cả các giao diện có sẵn .

  2. Đối với một máy chủ, bạn thường muốn liên kết với tất cả các giao diện - không chỉ "localhost".

  3. Nếu bạn chỉ muốn liên kết socket của mình với localhost, thì cú pháp sẽ là my_sockaddress.sin_addr.s_addr = inet_addr("127.0.0.1");, sau đó gọi bind(my_socket, (SOCKADDR *) &my_sockaddr, ...).

  4. Khi nó xảy ra, INADDR_ANYlà một hằng số xảy ra bằng "không":

    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. Nếu bạn chưa quen thuộc với nó, tôi khuyên bạn nên xem Hướng dẫn Lập trình Sockets của Beej:

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

Vì mọi người vẫn đang đọc cái này, một lưu ý bổ sung:

người đàn ông (7) ip :

Khi một tiến trình muốn nhận các gói hoặc kết nối mới, nó phải liên kết một socket với một địa chỉ giao diện cục bộ bằng cách sử dụng bind (2) .

Trong trường hợp này, chỉ một ổ cắm IP có thể được liên kết với bất kỳ cặp cục bộ (địa chỉ, cổng) nào. Khi INADDR_ANY được chỉ định trong lệnh gọi liên kết, socket sẽ được liên kết với tất cả các giao diện cục bộ.

Khi nghe (2) được gọi trên một ổ cắm không liên kết, ổ cắm sẽ tự động được liên kết với một cổng miễn phí ngẫu nhiên với địa chỉ cục bộ được đặt thành INADDR_ANY.

Khi kết nối (2) được gọi trên một ổ cắm không liên kết, ổ cắm sẽ tự động được liên kết với một cổng miễn phí ngẫu nhiên hoặc với một cổng chia sẻ có thể sử dụng được với địa chỉ cục bộ được đặt thành INADDR_ANY ...

Có một số địa chỉ đặc biệt: INADDR_LOOPBACK (127.0.0.1) luôn tham chiếu đến máy chủ cục bộ thông qua thiết bị loopback; INADDR_ANY (0.0.0.0) có nghĩa là bất kỳ địa chỉ nào để ràng buộc ...

Cũng thế:

bind () - Liên kết tên với một ổ cắm :

Nếu trường (sin_addr.s_addr) được đặt thành hằng số INADDR_ANY, như được định nghĩa trong netinet / in.h, người gọi yêu cầu rằng socket được liên kết với tất cả các giao diện mạng trên máy chủ. Sau đó, các gói UDP và kết nối TCP từ tất cả các giao diện (khớp với tên liên kết) được chuyển đến ứng dụng. Điều này trở nên quan trọng khi một máy chủ cung cấp dịch vụ cho nhiều mạng. Bằng cách để địa chỉ không xác định, máy chủ có thể chấp nhận tất cả các gói UDP và các yêu cầu kết nối TCP được thực hiện cho cổng của nó, bất kể giao diện mạng mà các yêu cầu đến.


4
Nó không có nghĩa là 'ràng buộc với tất cả các giao diện'. Nếu nó làm như vậy, đầu ra netstat sẽ khác. Nó có nghĩa là 'nghe ở bất kỳ giao diện nào '.
Marquis of Lorne

6
Để trích dẫn liên kết ở trên: "Khi INADDR_ANY được chỉ định trong lệnh gọi liên kết, ổ cắm sẽ được liên kết với tất cả các giao diện cục bộ." Từ một liên kết khác: Giá trị "INADDR_ANY" có nghĩa là chúng tôi sẽ liên kết với bất kỳ / tất cả các địa chỉ IP mà máy tính cục bộ hiện có . Nhưng có - nhiều triển khai sẽ liên kết với giao diện đầu tiên , (không phải "tất cả"). Nhưng đối với một PC với một NIC, sự khác biệt là tính học thuật. Với INADDR_ANY, máy khách có thể kết nối với bất kỳ / tất cả các IP (ví dụ: cả 192.168.1.2 và 127.0.0.1).
paulsm4

5
Xin lỗi nếu đây là một câu hỏi ngu ngốc, nhưng giao diện có nghĩa là không dây, ethernet, v.v.?
mrQWERTY

3
@ laike9m Bạn sẽ liên kết với 127.0.0.1 khi bạn muốn chỉ có thể kết nối với ổ cắm từ máy cục bộ. Có những trường hợp sử dụng cho việc này khi dịch vụ được cung cấp bởi ổ cắm chỉ nhằm mục đích được sử dụng bởi một quy trình khác cục bộ với máy.
dgnuff

2
@ paulsm4 Trong 3, bạn không thể sử dụng INADDR_LOOPBACK, thay vì inet_addr("127.0.0.1")?
John Strood,

62

INADDR_ANYđược sử dụng khi bạn không cần liên kết socket với một IP cụ thể. Khi bạn sử dụng giá trị này làm địa chỉ khi gọi bind(), ổ cắm sẽ chấp nhận kết nối với tất cả các IP của máy.


8

Để liên kết socket với localhost , trước khi bạn gọi hàm bind , trường sin_addr.s_addr của cấu trúc sockaddr_in phải được đặt đúng cách. Giá trị thích hợp có thể nhận được bằng cách

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

hoặc bằng cách

my_sockaddress.sin_addr.s_addr=htonl(INADDR_LOOPBACK);

4

INADDR_ANYhướng dẫn socket lắng nghe để liên kết với tất cả các giao diện có sẵn. Nó cũng giống như cố gắng ràng buộc với inet_addr("0.0.0.0"). Để đầy đủ, tôi cũng sẽ đề cập rằng cũng có IN6ADDR_ANY_INIT cho IPv6 và nó giống như việc cố gắng liên kết với ::địa chỉ cho ổ cắm IPv6.

#include <netinet/in.h>

struct in6_addr addr = IN6ADDR_ANY_INIT;

Ngoài ra, lưu ý rằng khi bạn liên kết ổ cắm IPv6 với ổ cắm IN6ADDR_ANY_INITcủa mình sẽ liên kết với tất cả các giao diện IPv6 và sẽ có thể chấp nhận các kết nối từ máy khách IPv4 (mặc dù địa chỉ được ánh xạ IPv6).


2

INADDR_ANY là một hằng số, chứa giá trị 0. điều này sẽ chỉ được sử dụng khi bạn muốn kết nối từ tất cả các cổng đang hoạt động mà bạn không quan tâm đến ip-add. vì vậy nếu bạn muốn kết nối bất kỳ ip cụ thể nào bạn nên đề cập như my_sockaddress.sin_addr.s_addr = inet_addr ("192.168.78.2")

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.