30/09/2018, 23:43

Giúp giải thích code C phần socket

Trong 2 hàm sau:

bind(socket,(struct sockaddr *)&server , sizeof(server));
hoặc
connect(socket,(struct sockaddr *)&client , sizeof(client))

struct sockaddr_in server hoặc struct sockadd_in client khi cast về struct sockaddr * thì thông tin Port number được đưa vào 2 hàm trên như thế nào ?

Hay việc này diễn ra ở đoạn nào khác? Mình thấy trong 2 tiến trình bind hoặc connect , truct sockaddr_in` không được sử dụng trực tiếp vào hàm nào?

Mai Anh Dũng viết 01:45 ngày 01/10/2018

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 bindconnect, ta ép kiểu struct sockaddr ngược về struct sockaddr_in.

anon45952904 viết 01:46 ngày 01/10/2018

Vậy mấu chốt của ép kiểu không phải là cấu trúc dữ liệu, hay type ( vd: struct, int, char…) mà là length?

Rất cảm ơn bác.

Mai Anh Dũng viết 01:43 ngày 01/10/2018

Có thể hiểu như vậy Ta có một chuỗi bytes. Đọc như thế nào, hiểu như thế nào là dựa vào struct mà mình ép xuống.

Ví dụ có chuỗi 4 bytes. Nếu ép về int, có nghĩa đó là 1 số nguyên 4 bytes. Nếu ép về char, thì đây là một chuỗi văn bản có 4 bytes (hoặc 3 bytes dữ liệu, 1 byte kết thúc chuỗi.)

anon45952904 viết 01:54 ngày 01/10/2018

Lý do cho sự tồn tại của struct sockaddr là gì? tại sao connectbind ko dùng luôn struct sockaddr_in?

Trong C, em chưa thấy struct sockaddr dùng với mục đích declaration mà chỉ dùng để cast, nếu thực sự cần nó tại sao không ẩn vào trong các hàm?

Mai Anh Dũng viết 01:44 ngày 01/10/2018

Lý do cho sự tồn tài của struct sockaddr là API. Một API phải có một interface rõ ràng, kiểu dữ liệu truyền vào cụ thể.

Hàm bindconnect có thể nhận vào IPv4 hoặc IPv6 hoặc kiểu Network Address khác. Vậy ta cần phải chọn một kiểu struct làm chuẩn. struct sockaddr là kiểu dữ liệu chuẩn cho API bindconnect.

Tuy nhiên, struct sockaddr có kích thước bằng với struct sockaddr_in, nhưng nhỏ hơn struct sockaddr_in6 và nhỏ hơn struct sockaddr_un. Thế nên ta cần thêm một giá trị nữa là length. Dựa vào length, ở đây là sizeof(server), ta sẽ biết là struct truyền vào có kích thước bao nhiêu. Hoặc có thể sử dụng member sa_family để biết loại network address là gì để ép kiểu trở lại kiểu ban đầu.

Tran Viet Anh viết 01:54 ngày 01/10/2018

hay quá ^^ cám ơn ad ^^

Bài liên quan
0