Trước hết mình xem qua các struct này được định nghĩa thế nào.
Đạt có đánh dấu số lượng byte theo sau mỗi member của struct.
struct sockaddr_in {
short sin_family; // e.g. AF_INET - 2 bytes
unsigned short sin_port; // e.g. htons(3490) - 2 bytes
struct in_addr sin_addr; // see struct in_addr, below - 4 bytes
char sin_zero[8]; // zero this if you want to - 8 bytes
};
struct in_addr {
unsigned long s_addr; // load with inet_aton() - 4 bytes
};
Như vậy, mình thấy được struct sockaddr_in
bao gồm 2 bytes đầu tiên là sin_family
, có thể hiểu là header, và 14 bytes tiếp theo là data.
Bây giờ mình xem qua struct sockaddr
struct sockaddr {
unsigned short sa_family; // address family, AF_xxx - 2 bytes
char sa_data[14]; // 14 bytes of protocol address
};
Ở đây mình thấy struct này cũng có 2 bytes đầu tiên là sa_family
tương đương với 2 bytes đầu tiên của struct sockaddr_in
là sin_family
. Hai bytes này để phân loại socket thuộc về họ gì, ví dụ như:
-
IF_INET
là IPv4
-
IF_INET6
là IPv6
Tiếp theo, ta thấy struct sockaddr
có 14 bytes kiểu char là một mảng. Một kỹ thuật hay được dùng trong network programming là dùng một array bytes để chứa dữ liệu(data). Khi ta cast struct sockaddr_in
, bất kể client hay server, hoặc struct sockaddr_in6
, dành cho IPv6, về dạng struct sockaddr
thì
-
2 bytes đầu vẫn là family của socket đấy như đã nói ở trên.
-
14 bytes tiếp theo sẽ nằm trong array
char sa_data[14]
. Khi muốn sử dụng chỉ cần gọi cái char sa_data[14]
ra ép kiểu là lấy được mọi giá trị ta cần như sin_port
, sin_addr
. Để ý ở đây, struct sockaddr_in
có char sin_zero[8]
, đây là phần thừa, không sử dụng. Người ta chỉ khai báo như vậy để phần data của struct này có độ dài giống như struct sockaddr_in6
mà thôi. Phần này không dùng trong IPv4.
Vậy làm sao có thể đọc được sin_port và sin_addr từ sa_data
Cách đơn giản nhất là trong hàm bind
và connect
, ta ép kiểu struct sockaddr
ngược về struct sockaddr_in
.