1.主机字节序和网络字节序
现在CPU的累加器一次能装载至少四字节,这四字节在内存中的排列顺序讲影响它被累加器装成的整数的值。现代PC大多采用小端字节序,所以被称为主机字节序。当不同字节序的主机传输问题时,会存在传输信息错误解释的结果。解决这个问题的方式就是:发送端要把发送的数据转化成大端字节序在网上传输,接收端知道网络传输都是大端所以要根据自身情况进行转化。大端叫网络字节序,小端叫主机字节序。
注意:即便同一台机器的两个进程通信,也要考虑大小端的问题,JAVA虚拟机采用的事大端字节序。通过测试,我的windows笔记本为小端。
#include<netinet/in.h>**
①unsigned long int htol (unsigned long int hostlong);
②unsigned short int htons(unsigned short int hostshort);
③unsigned long int ntohl(unsigned long int netlong);
④unsigned short int ntohs(unsigned short int netshort);
任何格式化数据通过网络传输时,都应该用这些函数转字节序!
判断大端小端的函数~~
#include <stdio.h>
void byteorder()
{
union
{
short value;
char union_bytes[ sizeof( short ) ];
} test;
test.value = 0x0102;
if ( ( test.union_bytes[ 0 ] == 1 ) && ( test.union_bytes[ 1 ] == 2 ) )
{
printf( "big endian\n" );
}
else if ( ( test.union_bytes[ 0 ] == 2 ) && ( test.union_bytes[ 1 ] == 1 ) )
{
printf( "little endian\n" );
}
else
{
printf( "unknown...\n" );
}
}
2.通用socket地址
#include<bits/socket.h>
/* Structure describing a generic socket address. */
struct sockaddr
{
sa_family_t sa_family; /* Common data: address family and length. 协议族 or 地址族*/
char sa_data[14]; /* Address data. 不同地址族有不同的长度和含义*/
};
/* Structure large enough to hold any socket address (with the historical
exception of AF_UNIX). */
struct sockaddr_storage
{
sa_family_t sa_family; /* Address family, etc. */
unsigned long int __ss_align; /* Force desired alignment. */
char __ss_padding[128-sizeof(__ss_align)];
};
sockaddr_storage结构体提供了足够大的空间用于存放地址族,而且内存是对齐的。
3.专用socket地址
Linux各协议族提供了专门的socket地址结构体。
unix本地域使用专门socket地址结构体:
#include<sys/un.h>
/* Structure describing the address of an AF_LOCAL (aka AF_UNIX) socket. */
struct sockaddr_un
{
// __SOCKADDR_COMMON (sun_);
sa_family_t sa_family; /* AF_UNIX. */
char sun_path[108]; /* Path name. */
};
TCP/IP协议族有专用的socketaddr_in和sockaddr_in6,分别用于ipv4和ipv6
#include <netinet/in.h>
/* Structure describing an Internet socket address. */
struct sockaddr_in
{
sa_family_t sin_family; /*地址族:AF_INET*/
in_port_t sin_port; /* Port number. */
struct in_addr sin_addr; /* Internet address. */
};
/* Internet address. */
typedef uint32_t in_addr_t;
struct in_addr
{
in_addr_t s_addr; //ipv4地址,要用网络字节序表示
};
/* Ditto, for IPv6. */
struct sockaddr_in6
{
sa_family_t sin6_family;
in_port_t sin6_port; /* Transport layer port # */
uint32_t sin6_flowinfo; /* IPv6 flow information */
struct in6_addr sin6_addr; /* IPv6 address */
uint32_t sin6_scope_id; /* IPv6 scope-id */
};
#endif /* !__USE_KERNEL_IPV6_DEFS */
所有专用的socket地址类型(sockaddr_storage)都需要强制转化为地址类型sockaddr,所有的socket编程接口使用的参数都是sockaddr。
4.IP地址转化函数
#include<arpa/inet.h>
①in_addr_t inet_addr(const char * strptr);
②int inet_aton(const char *cp,struct in_addr* inp);
③char* inet_ntoa(struct in_addr in);
inet_addr函数用 点分十进制字符串 表示的IPv4地址转化为用网络字节序整数表示的IPv4地址。它失败时返回INADDR_NONE。
inet_aton函数完成和inet_addr同样的功能,但将结果存储于参数inp指向的地址结构体中。成功返回1,失败返回0.
inet_ntoa函数讲用网络字节序整数表示的IP地址转化为用 点分十进制字符串表示的IPv4地址。需要注意的是:该函数内部用一个静态变量存储转化结果,函数返回值指向该静态内存,所以是不可重入的。
#include<arpa/inet.h>
④int inet_pton(int af,const char * src,void *dst);
⑤const char* inet_ntop(int af,const void* src,char * dst,socklen_t cnt);
inet_pton函数将用字符串表示的IP地址src(用点分十进制字符串表示的IPv4地址或用十六进制字符串表示的IPv6地址)转化成用网络字节序证书表示的IP地址,并把转换结果存储于dst指向的内存中。其中,af参数指定地址族,可以是AF_INET或者AF_INET6。成功返回1,失败返回0并设置errno。
inet_ntop函数进行相反的转换,前三个参数的含义与inet_pton的参数相同,最后一个参数cnt指定目标存储单元的大小。成功时返回目标存储单元的地址,失败返回NULL并设置errno。指定大小的两个宏。
#include<netinet/in.h>
#define INET_ADDRSTRLEN 16
#define INET6_ADDRSTRLEN 46