2015-09-17 18 views
5
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen); 

Cấu trúc thực tế được chuyển cho đối số bổ sung sẽ phụ thuộc vào họ địa chỉ. Cấu trúc sockaddr được định nghĩa là một cái gì đó như:Mục đích của trường sa_data trong sockaddr là gì?

struct sockaddr { 
    sa_family_t sa_family; 
    char  sa_data[14]; 
} 

Vì vậy, đối với một địa chỉ IPv4 (AF_INET), các cấu trúc thực tế sẽ được thông qua là thế này:

/* Source http://linux.die.net/man/7/ip */ 

struct sockaddr_in { 
    sa_family_t sin_family; /* address family: AF_INET */ 
    in_port_t  sin_port; /* port in network byte order */ 
    struct in_addr sin_addr; /* internet address */ 
}; 

/* Internet address. */ 
struct in_addr { 
    uint32_t  s_addr;  /* address in network byte order */ 
}; 

Liệu mã bind đọc giá trị sockaddr.sa_family và tùy thuộc vào giá trị mà nó tìm thấy, sau đó nó sẽ đúc cấu trúc sockaddr vào cấu trúc thích hợp như sockaddr_in?

Tại sao sa_data đặt thành 14 ký tự? Nếu tôi hiểu chính xác, trường sa_data chỉ là một trường có dung lượng bộ nhớ đủ lớn để phù hợp với tất cả các loại gia đình địa chỉ? Có lẽ các nhà thiết kế ban đầu dự đoán rằng 14 ký tự sẽ đủ rộng để phù hợp với tất cả các loại trong tương lai.

+0

https://en.wikipedia.org/wiki/Type_punning – user3386109

Trả lời

5

Theo glibc manual:

Chiều dài 14 sa_data là bản chất độc đoán.

FreeBSD developers handbook đề cập đến sau đây:

Xin lưu ý sự mơ hồ mà lĩnh vực sa_data được khai báo, cũng giống như một mảng của 14 byte, với những nhận xét gợi ý có thể có hơn 14 trong số đó.

Sự mơ hồ này khá thận trọng. Ổ cắm là giao diện rất mạnh mẽ. Trong khi hầu hết mọi người có lẽ nghĩ rằng nó không có gì hơn giao diện Internet - và hầu hết các ứng dụng có thể sử dụng nó cho ngày ngày nay - ổ cắm có thể được sử dụng cho bất kỳ loại liên lạc nào. , IP) chỉ là một.

Có, trường sa_family được sử dụng để nhận biết cách xử lý cấu trúc được truyền tới (struct sockaddr* trong cuộc gọi đến ràng buộc). Bạn có thể đọc thêm về cách nó hoạt động trong một số FreeBSD developers handbook.

Và trên thực tế có "đa hình" (sub) loại sockaddr, trong đó sa_data chứa hơn 16 byte, ví dụ:

struct sockaddr_un { 
    sa_family_t sun_family;    /* AF_UNIX */ 
    char  sun_path[108];   /* pathname */ 
}; 
3

Các sockaddr struct được sử dụng như một liên minh gắn thẻ. Bằng cách đọc trường sa_family, nó có thể được đúc thành một cấu trúc của biểu mẫu thích hợp.

14 byte là tùy ý. Đủ lớn để giữ địa chỉ IPv4, nhưng không đủ lớn để giữ địa chỉ IPv6. Ngoài ra còn có cấu trúc sockaddr_storage đủ lớn cho cả hai. Đọc tài liệu của Microsoft trên SOCKADDR_STORAGE, nó có kích thước 128 byte, lớn hơn nhiều so với IPv6 cần thiết. Kiểm tra một số tiêu đề Linux, nó có vẻ là ít nhất là lớn ở đó là tốt.

Để tham khảo, các cấu trúc IPv6 là:

struct sockaddr_in6 { 
    u_int16_t  sin6_family; // address family, AF_INET6 
    u_int16_t  sin6_port;  // port number, Network Byte Order 
    u_int32_t  sin6_flowinfo; // IPv6 flow information 
    struct in6_addr sin6_addr;  // IPv6 address 
    u_int32_t  sin6_scope_id; // Scope ID 
}; 

struct in6_addr { 
    unsigned char s6_addr[16]; // IPv6 address 
}; 

Như bạn có thể thấy, 16 byte s6_addr lĩnh vực đã được lớn hơn 14 byte sa_data lĩnh vực trên riêng của nó. Tổng kích thước sau trường sa_family là 26 byte.