struct in_addr{
in_addr_t s_addr; /* 32-bit IPv4 address */
/* network byte ordered */
};
struct sockaddr_in{
uint_t sin_len; /* length of struct ure (16) */sa_family_t sin_family; /* AF_INET */in_port_t sin_port; /* 16-bit TCP or UDP port number */struct in_addr sin_addr; /* 32-bit IPv4 address */char sin_zero[8]; /* unused */
};
sin_len:为了增加对OSI协议的支持而随4.3BSD-Reno添加的。在这之前sin_family是第一个字段,不是所有的系统都支持长度字段,POSIX 规范不要求这个字段。sin_len字段简化了长度可变套接字地址结构的处理。除 非涉及路由套接字,否则不需要设置sin_len字段。
sin_family:套接字地址结构的地址族。用来标识是IPv4或者IPv6抑或其他类型。必须设置。
sin_port: 套接字所要使用的端口号。必须设置
sin_addr:套接字所要用到的32位的IPv4地址。必须设置
sin_zero:未使用,捆绑非通配地址时必须置零
(4)POSIX定义的数据类型:
数据类型 说明 头文件
int8_t 带符号的8位整数 <sys/types.h>
uint8_t 无符号的8位整数 <sys/types.h>
int16_t 带符号的16位整数 <sys/types.h>
uint16_t 无符号的16位整数 <sys/types.h>
int32_t 带符号的32位整数 <sys/types.h>
uint32_t 无符号的32位整数 <sys/types.h>
sa_familu_t 套接字地址结构的地址族 <sys/socket.h>
socklen_t 套接字地址结构的长度(uint32_t) <sys/socket.h>
in_addr_t IPv4地址(uint32_t) <netinet/in.h>
in_port_t TCP或UDP端口号(uint16_t) <netinet/in.h>
(5)IPv4地址和TCP或UDP端口号在套接字地址结构中是以网络字节序存放的。
(6)IPv4地址存在2种访问方法:
((1))按结构方式引用IPv4 地址 struct.sin_addr
((2))按32位数值方式引用IPv4地址 struct.sin_addr.s_addr
(7)套接字地址结构仅在本机使用,结构本身不在网络上传递。
3.2.2 通用套接字地址结构
(1)存在通用套接字地址结构的原因是:在调用任何需要套接字地址结构做为参数的函数时,套接字地址结构总是以引用的方式(指针)传递的。不同的协议有不同的套接字地址结构,函数的参数怎么声明这些套接字地址结构的指针类型是一个问题,于是就定义了一个通用套接字地址结构,所有需要套接字地址结构做参数的函数的这个形参都被声明为指向这个通用套接字地址结构的指针的类型。其他套接字地址结构的指针被强制转换为通用套接字地址结构的指针类型。(ANSI C 定义了 void * 来解决这个问题)
(2)通用套接字地址结构定义在<sys/socket.h>:
struct sockaddr {
uint8_t sa_len;
sa_family_t sa_family;
char sa_data[14];
};
3.2.3 IPv6套接字地址结构
(1)IPv6套接字地址结构在<netinet/in.h>中定义。
(2)IPv6套接字地址结构:
struct in6_addr {
uint8_t s6_addr[16];
};
#define SIN6_LEN
struct sockaddr_in6 {
uint8_t sin6_len;
sa_family_t AF_INET6;
in_port_t sin6_port;
uint32_t sin6_flowinfo;
struct in6_addr sin6_addr;
uint32_t sin6_scope_id;
};
关于IPv6套接字地址结构的说明:
((1))如果当前系统支持套接字地址结构中的长度字段,则SIN6_LEN常值必须定义。
((2))IPv6的地址族是AF_INET6 而IPv4 是AF_INET.
3.2.4 新的通用套接字地址结构
(1)新的通用套接字地址结构定义在<netinet/in.h>中
(2)新的通用套接字地址结构:
struct sockaddr_storage {
uint8_t ss_len;
sa_family_t ss_family;
/* 其它字段对用户是透明的*/
};
(3)对新的通用套接字地址结构的几点说明:
((1))新的通用套接字地址结构满足对齐要求
((2))新的通用套接字地址结构足够大,能够容纳系统支持的任何套接字地址结构。
((3))sockaddr_storage 结构必须类型强制转换成或复制到适合于ss_family字段所给出地址类型的套接字地址结构中,才能访问其他字段。
3.4字节排序函数
(1)大端字节序(big-endian)将一个16位数的高位字节存储在起始地址称为大端字节序。
(2)小端字节序(little-endian)将一个16位数的低位字节存储在起始地址称为小端字节序。
(3)网络字节序就是大端字节序。
(4)在网络字节序和主机字节序之间转换的函数,它们在<netinet/in.h>中声明
uint16_t htons(uint16_t host16bitvalue);
uint32_t htonl(uint32_t host32bitvalue);
uint16_t ntohs(uint16_t net16bitvalue);
uint32_t ntohl(uint32_t net32bitvalue);
当使用这些函数时,并不用关心主机字节序和网络字节序的真实值(大端。小端),只要调用相应的函数在主机字节序和网络字节序之间转换某个给定值。在那些与网际协议所用字节序(大端)相同的系统中,这四个函数通常被定义为空宏。
3.5 字节操纵函数
(1)字节操纵函数并不假设数据是以0结尾的C字符串。操纵C字符串的函数在<string,h>中声明,名字以str开头。
(2)Berkeley版本的字节操纵函数声明在<strings.h>中
void *memset(void *dest, int c, size_t len);void bzero(void dest *, size_t nbytes);
void bcopy(const void *str, void *dest, size_t nbytes);
int bcmp(const void *ptr1, const void *ptr2, size_t nbytes); /*相等返回0,不相等返回非0*/
(3)ANSI C版本的字节操纵函数声明在<string.h>中
void *memcpy(void *dest, const void *src, size_t nbytes);
int memcmp(const void *ptr1, const void *ptr2, size_t nbytes); /*相等返回0,否则非0 是大于0还是小于0取决于第一个不等的字节*/
3.6 地址转换函数
(1)地址转换函数在地址的ASCII字符串和网络字节序的二进制值之间进行转换。
(2)地址转换函数在<arpa/inet.h>中进行声明。
(3)只适用于IPv4的地址转换函数
int inet_aton(cosnt char *strptr, struct in_addr *addrptr); /* 成功返回1,否则返回0*/
in_addr_r inet_addr(const char *strptr); (废弃不用)/* 如果参数有效,成功返回32位二进制网络字节序IPv4地址,否则返回INADDR——NONE*/
char *inet_ntoa(struct in_addr inaddr); /* 返回值指向一个点分十进制数串,不可重入,*/
(4)同时适合IPv4和IPv6的地址转换函数
int inet_pton(int family, const char *strptr, void *addrstr); /* 成功返回1,输入不是有效表达式返回0,错误返回-1*/
const char *inet_ntop(int family, const void *addrstr, char *strptr ,size_t len); /* 成功返回指向结果的指针,失败指针为NULL*/
/* family 参数可以是AF_INET 或者AF_INET6 如果传入不被支持的地址族,函数返回错误,并设置errno 为EAFNOSUPPORT。
len 参数指明了 strptr 所指向的缓冲区的大小,从而避免缓冲区溢出.如果len参数太小,不能容纳结果,函数返回空指针,并设
置errno为ENOSPC。
在<netinet/ih.h>头文件中定义了len的两个常量 IPv4 : #define INET_ADDRSTRLEN 16
IPv6 :#define INET6_ADDRSTRLEN 46
void *strptr 参数不能为NULL,调用者必须为这个参数分配空间。调用成功时这个指针就是函数的返回值。
*/
.