1. IPV4地址结构:
#include <netinet/in.h> struct in_addr { int_addr_t s_addr; //一般为uint32_t }; struct sockaddr_in { uint8_t sin_len; //一般用不上 sa_family_t sin_family; //通常是uint_8 in_port_t sin_port; //一般为uint16_t struct int_addr sin_addr; char sin_zero[8]; }
2. 地址和端口号一般以网络字节序来存储。
3. 通用套接字地址结构:
#include <sys/socket.h> struct sockaddr { uint8_t sa_len; sa_family_t sa_family; char sa_data[14]; }
通过sa_family值确定此结构的真实类型
4. ipv6地址结构
struct in6_addr { uint8_t s6_addr[16]; }; struct sockaddr_in6 { uint8_t sin6_len; sa_family_t sin6_family; /* AF_INET6 */ in_port_t sin6_port; /* port number */ uint32_t sin6_flowinfo; /* IPv6 flow information */ struct in6_addr sin6_addr; /* IPv6 address */ uint32_t sin6_scope_id; /* Scope ID (new in 2.4) */ };
套接字地址结构比较图
5. 值-结果参数的含义:
如有以下函数调用:
struct AAA st;
int len = sizeof(st);
func(&st, &len)
len是结构st的大小,用于防止func函数内部引用st时越界,函数返回时会通过len值告诉调用者,func函数存储了st中多少信息。如select,getsockopt,recvmsg,sysctl等函数中有这种应用。
6. 字节排序,little-endian与big-endian
#include <netinet/in.h> //主机字节序转换为网络字节序 uint16_t htons(uint16_t host_value); uint32_t htonl(uint32_t host_value); //网络字节序转换为主机字节序 uint16_t ntohs(uint16_t net_value); uint32_t ntohl(uint32_t net_value);
判断系统所用字节序程序:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
int main() { union { short s; char c[sizeof(short)]; }un; un.s = 0x0102; if (sizeof(short) == 2) { if (un.c[0] == 1 && un.c[1] == 2) { printf("big-endian\n"); } else if (un.c[0] == 2 && un.c[1] == 1) { printf("little-endian\n"); } else { printf("unknown\n"); } } else { printf("sizeof(short) = %d\n", sizeof(short)); } return 0; }
7. 字节操作函数
1)Berkeley的函数
#include <string.h> void bzero(void *dest, size_t nbytes); void bcopy(const void *src, void *dest, sizt_t nbytes); int bcmp(const void *ptr1, const void *ptr2, size_t nbytes);
2)ANSI C的函数
#include <string.h> void *memset(void *dest, int c, size_t len); void *memcpy(void *dest, const void *src, size_t nbytes); int memcmp(const void *ptr1, const void *ptr2, size_t nbytes);
两者比较 : memcpy与bcopy参数位置相反,当源字符串和目标字符串重叠时bcopy能处理而memcpy则不能,需要用memmove代替。
8. 地址转换函数
1)适用于ipv4
#include <arpa/inet.h> //有效返回1,否则返回0 int inet_aton(const char *strptr, struct in_addr *addrptr); //注意为什么参数为结构而不是指针? char *inet_ntoa(struct in_addr inaddr); in_addr_t inet_addr(const char *strptr); //此函数已废弃,不要用
2)ipv4,ipv6均适用
#include <arpa/inet.h> //返回:成功1,输入有误0,出错-1 int inet_pton(int family, const char *strptr, void *addrptr); //返回:成功返回指向结果指针,失败返回NULL const char *inet_ntop(int family, const void *addrptr, char *strptr, size_t len);
strptr的长度len在<netinet/in.h>头文件中有如下定义:
#define INET_ADDRSTRLEN 16
#define INET6_ADDRSTRLEN 46
总结:即使系统不支持IPv6也要用后面两个函数代替只支持ipv4的函数,保证代码与协议的无关性。
9. sock_ntop函数及相关函数是非标准库函数,此系列函数是为了方便编写与IPv4和IPv6协议无关的代码而封装的函数。