套接字地址结构
IPV4 <netinet/in.h> struct sockaddr_in { unsigned short sin_len; //IPv4地址长度 short int sin_family; //指代协议簇,在TCP套接字编程只能是AF_INET unsigned short sin_port; //存储端口号(使用网络字节顺序),数据类型是一个16为的无符号整形类型 struct in_addr sin_addr;//存储IP地址,IP地址是一个in_add结构体(结构在下面) unsigned char sin_zero[8]; //为了让sockaddr与sockaddr_in两个数据结构保持大小相同而保留的空字节 }; struct in_addr { unsigned long s_addr; //按照网络字节顺序存储IP地址 }; 老式结构 struct sockaddr { unsigned short sa_family; //套接字的协议簇地址类型,TCP/IP协议对于IPv4地址类型为AF_INET char sa_data[14];//存储具体的协议地址 };
示例
struct sockaddr_in serveraddr; bzero(&serveraddr, sizeof(serveraddr)); serveraddr.sin_family = AF_INET; inet_pton(AF_INET, ipstr, &serveraddr.sin_addr.s_addr); serveraddr.sin_port = htons(SERVER_PORT); connect(confd, (struct sockaddr *)&serveraddr, sizeof(serveraddr));
IPV6 <netinet/in.h> struct sockaddr_in6 { unsigned short int sin6_len; //IPv6结构长度,是一个无符号的8为整数,表示128为IPv6地址长度 short int sin6_family; //地址类型AF_INET6 unsigned short int sin6_port; //存储端口号,按网络字节顺序 unsigned short int sin6_flowinfo; //低24位是流量标号,然后是4位的优先级标志,剩下四位保留 struct in6_addr sin6_addr; //IPv6地址,网络字节顺序 }; struct in6_addr { unsigned long s6_addr; //128位的IPv6地址,网络字节顺序 };
字节序转换
大端模式和小端模式
1)小端就是低位字节排放在内存的低地址端,高位字节排放在内存的高地址端。
2)大端就是高位字节排放在内存的低地址端,低位字节排放在内存的高地址端。
举一个例子,比如数字0x12 34 56 78在内存中的表示形式为:
A. 大端模式:
低地址 -----------------> 高地址
0x12 | 0x34 | 0x56 | 0x78
B. 小端模式:
低地址 ------------------> 高地址
0x78 | 0x56 | 0x34 | 0x12
字节操作函数
#include <strings.h> void bzero(void *dest, size_t nbytes); void bcopy(const void *src, void *dest, size_t nbytes); int bcmp(const void *ptrl, const void *ptr2, size_t nbytes);返回值:若相等则为0,否则为非0
bzero把目标字节串中指定数目的字节置为0。我们经常使用该函数来把一个套接字结构初始化为0。bcopy将指定数目的字节从源字节串移到目标字节串。bcmp比较两个任意的字节串,若相同则返回值为0,否则返回值为非0。
#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);返回值:若相等则为0,否则为<0或>0
IP地址转换函数
IP地址转换函数是指完成点分十进制IP地址与二进制IP地址之间的相互转换。IP地址转换主要由inet_addr、inet_aton和inet_ntoa这3个函数完成,但这三个函数都只能处理IPv4地址而不能处理IPv6地址。新的函数inet_pton跟inet_ntop则同时处理IPv4和IPv6。
1)inet_pton 注:pton:presentation to numeric inet_pton函数原型如下[将"点分十进制" -> "整数"] #include <sys/types.h> #include <sys/socket.h> #include <arpa/inet.h> int inet_pton(int af, const char *src, void *dst); //这个函数转换字符串到网络地址,第一个参数af是地址族,转换后存在dst中 //若成功则返回1;若输入不是有效的表达式则返回0;若出错则返回-1。
2)inet_ntop inet_ntop函数原型如下[将"点分十进制" -> "整数"] #include <sys/types.h> #include <sys/socket.h> #include <arpa/inet.h> const char *inet_ntop(int af, const void *src, char *dst, socklen_t cnt); //这个函数转换网络二进制结构到ASCII类型的地址,参数的作用和上面相同,只是多了一个参数socklen_t cnt, //它是所指向缓存区dst的大小,避免溢出,如果缓存区太小无法存储地址的值,则返回一个空指针,并将errno置为ENOSPC。 //若成功则返回指向结果的指针,若出错则返回NULL。
char IPdotdec[20]; // 存放点分十进制IP地址 struct in_addr s; // IPv4地址结构体 // 输入IP地址 printf("Please input IP address: "); scanf("%s", &IPdotdec); // 转换 inet_pton(AF_INET, IPdotdec, (void *)&s); printf("inet_pton: 0x%x ", s.s_addr); // 注意得到的字节序 // 反转换 inet_ntop(AF_INET, (void *)&s, IPdotdec, 16); printf("inet_ntop: %s ", IPdotdec);
3)inet_aton
aton:address to network
4)inet_ntoa
5)inet_addr(该函数无法处理255.255.255.255的IP地址,已弃用)