Русские Блоги
Две структуры struct sockaddr и struct sockaddr_in используются для обработки адреса сетевого взаимодействия.
Один, sockaddr
sockaddr в заголовочном файле #include В определении недостаток sockaddr: sa_data смешивает целевой адрес и информацию о порте следующим образом:
Во-вторых, sockaddr_in
sockaddr_in в заголовочном файле #include или #include Определенная в, эта структура устраняет дефект sockaddr, порт и addr хранятся отдельно в двух переменных следующим образом:
Другая структура in_addr, упомянутая в этой структуре, определяется следующим образом: она используется для хранения 32-битного IP-адреса.
// // IPv4 Internet address // This is an 'on-wire' format structure. // typedef struct in_addr < union < struct < UCHAR s_b1,s_b2,s_b3,s_b4; >S_un_b; struct < USHORT s_w1,s_w2; >S_un_w; ULONG S_addr; > S_un; #define s_addr S_un.S_addr /* can be used for most tcp & ip code */ #define s_host S_un.S_un_b.s_b2 // host on imp #define s_net S_un.S_un_b.s_b1 // network #define s_imp S_un.S_un_w.s_w2 // imp #define s_impno S_un.S_un_b.s_b4 // imp # #define s_lh S_un.S_un_b.s_b3 // logical host > IN_ADDR, *PIN_ADDR, FAR *LPIN_ADDR;
И sin_port, и sin_addr должны быть в порядке сетевых байтов (NBO, сетевой порядок байтов), а общие визуальные числа — в порядке байтов хоста (HBO, порядок байтов хоста).
3. Резюме
Оба имеют одинаковую длину, оба имеют размер 16 байт, то есть размер памяти одинаков, поэтому они могут быть преобразованы друг в друга. Это две параллельные структуры, и указатель на структуру sockaddr_in также может указывать на sockaddr.
sockaddr часто используется в параметрах bind, connect, recvfrom, sendto и других функций для указания адресной информации, которая является общим адресом сокета.
sockaddr_in — это адресная форма сокета в интернет-среде. Поэтому в сетевом программировании мы будем работать со структурой sockaddr_in, использовать sockaddr_in для установки необходимой информации и, наконец, использовать преобразование типов. Обычно после присвоения переменной sockaddr_in преобразование типа передается в функцию, которая использует sockaddr в качестве параметра: sockaddr_in используется для определения и назначения сокета, sockaddr — для параметров функции.
#include #include #include #include int main(int argc,char **argv) < int sockfd; struct sockaddr_in mysock; sockfd = socket(AF_INET,SOCK_STREAM,0); // Получить ФД bzero (& mysock, sizeof (mysock)); // Инициализировать структуру mysock.sin_family = AF_INET; // Установить семейство адресов mysock.sin_port = htons(800); // Установить порт mysock.sin_addr.s_addr = inet_addr("192.168.1.0"); // Установить адрес bind (sockfd, (struct sockaddr *) и mysock, sizeof (struct sockaddr); / * Конвертировать при связывании * / . . return 0; >
Не по теме, две функции htons () и inet_addr ().
Роль htons () — преобразовать номер порта из порядка байтов хоста в целочисленное значение порядка байтов сети. (хост к сети)
Функция inet_addr () — преобразовать строку IP в целочисленное значение порядка байтов в сети, которое используется для sockaddr_in.sin_addr.s_addr.
Функция inet_ntoa () — вывести структуру sin_addr в виде строки IP (от сети до ascii). Такие как:
printf("%s",inet_ntoa(mysock.sin_addr));
htonl () — это то же самое, что и htons (), но для 32-битного (long) и htons () для двух байтов, 16-bit (short).
Две функции, противоположные htonl () и htons (): ntohl () и ntohs ().
Why can we cast sockaddr to sockaddr_in
I can see why it is useful to cast sockaddr to sockaddr_in , but I don’t understand how this is possible. From what I’ve read, they’re the same size and sockaddr_in is added with sin_zero to make it the same size. I would like to know how the compiler knows where to get the information from sockaddr_in if it is layed out differently to sockaddr .
1 Answer 1
It is possible because you normally cast pointers, not the structures themselves. You do what in natural language means «please treat this pointer to a socket structure as a pointer to an internet socket structure instead». Compiler has no problems to re-interpret the pointer.
Here is more detailed description taken up from comments:
A sockaddr is 16 bytes in size — the first two bytes are the sa_family , and the remaining 14 bytes are the sa_data which is arbitrary data. A sockaddr_in is also 16 bytes in size — the first 2 bytes are the sin_family (always AF_INET ), the next 2 bytes are the sin_port , the next 4 bytes are the sin_addr (IP address), and the last 8 bytes are the sin_zero which is unused in IPv4 and provided only to ensure 16 bytes. This way, you can look at sockaddr.sa_family first, and if it is AF_INET then interpret the entire sockaddr as a sockaddr_in .
A sockaddr_in is not stored inside of sockaddr.sa_data field. The entire sockaddr is the entire sockaddr_in (when sockaddr.sa_family is AF_INET , that is). If you take a sockaddr* pointer and cast it to a sockaddr_in* pointer, then:
- sockaddr.sa_family is sockaddr_in.sin_family
- bytes 0-1 of sockaddr.sa_data are sockaddr_in.sin_port
- bytes 2-5 are sockaddr_in.sin_addr
- bytes 6-13 are sockaddr_in.sin_zero .