不同体系结构的主机使用不同的字节存储。字节存储顺序不同,有的是高位在前,低位在后;有的高位在后,低位在前。按照这种区分方法,字节序分为大端字节序和小端字节序。在网络上传输,采用网络字节序,网络字节序采用大端字节序。如下图所示:
网络传输的数据大家一定要统一,所以对于机器内部表示顺序和网络字节顺序不同的机器,就一定要对数据进行转换。
uint32_t htonl(uint32_t hostlong); // 将一个32位整数由主机字节序转换成网络字节序。
uint16_t htons(uint16_t hostshort); // 将一个16位整数由主机字节序转换成网络字节序
uint32_t ntohl(uint32_t netlong); // 将一个32位整数转换成主机字节序
uint16_t ntohs(uint16_t netshort); //将一个16位整数转换成主机字节序
通用地址结构
#include <sys/socket.h>
struct sockaddr
{
unsigned short sa_family; /* internet地址族 AF_INET等 */
char sa_data[14]; /* 14字节的协议地址 */
};
sa_data包含了一些远程电脑的地址、端口、套接字的数目
sa_family一般来说,选用的协议类型,ipv4选用AF_INET,ipv6选用AF_INET6
在传递给需要地址结构的函数时,把指向该结构体的指针转换成(struct sockaddr*)传递进去。
struct in_addr
{
in_addr_t s_addr; /*ipv4地址*/
};
struct sockaddr_in
{
short int sin_family; // internet地址族如 AF_INET, AF_INET6, AF_UNIX
unsigned short int sin_port; //端口号,16位(网络字节序)
struct in_addr sin_addr; // internet地址,32位ipv4地址,网络字节序
unsigned char sin_zero[8]; // 添加0,填充对齐
};
这两个数据类型等效,可以相互转换,通常使用sockaddr_in,更为方便。
ipv4地址族和字符地址间的转换
#include <arp/inet.h>
/*网络字节序转换成点分十进制,成功返回地址字符串的指针,出错返回Null。*/
const char *inet_ntop(int domain, const void *addr, char *str, socklen_t size);
/*点分十进制转换成网络字节序,成功返回1,无效格式返回0,出错返回-1*/
int inet_pton(int domain ,const char *str, void *addr);
示例代码:
struct sockaddr_in sin;
char buffer[16];
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_port = htons((short int)3001);
if(inet_pton(AF_INET, "192.168.1.1", &sin.sin_addr.s_addr) <= 0)
{
// 错误处理
}
inet_ntop(AF_INET, &sin.sin_addr.s_addr, buf, sizeof(buf));