socket编程 sockaddr sockaddr_in
Windows下与Linux下编写socket程序的区别
http://blog.chinaunix.net/uid-2270658-id-308160.html
sockaddr_in , sockaddr , in_addr区别Socket编程函数集(非常有用)
http://810364804.iteye.com/blog/2094531
ntohs, ntohl, htons,htonl的比较和详解
http://www.360doc.com/content/12/0222/10/54470_188560773.shtml
struct sockaddr和struct sockaddr_in这两个结构体用来处理网络通信的地址。
在各种系统调用或者函数中,只要和网络地址打交道,就得用到这两个结构体。
include <netinet/in.h>
//sockaddr是给操作系统使用
struct sockaddr {
unsigned short sa_family; // 2 bytes address family, AF_xxx,sa_family是地址家族,一般都是“AF_xxx”的形式。通常大多用的是都是AF_INET,代表TCP/IP协议族
char sa_data[14]; // 14 bytes of protocol address
};
// IPv4 AF_INET sockets:
//程序员应使用sockaddr_in来表示地址,sockaddr_in区分了地址和端口
struct sockaddr_in {
short sin_family; // 2 bytes e.g. AF_INET, AF_INET6
//sockaddr用其余14个字节来表示sa_data, sockaddr_in把14个字节拆分成sin_port, sin_addr和sin_zero
unsigned short sin_port; // 2 bytes e.g. htons(3490), 端口号
struct in_addr sin_addr; // 4 bytes see struct in_addr, below, IP 地址
char sin_zero[8]; // 8 bytes zero this if you want to, sin_zero用来填充字节使sockaddr_in和sockaddr保持一样大小
};
struct in_addr {
unsigned long s_addr; // 4 bytes load with inet_pton()
};
typedef struct in_addr {
union {
struct{ unsigned char s_b1, s_b2, s_b3, s_b4; } S_un_b;
struct{ unsigned short s_w1, s_w2; } S_un_w;
unsigned long S_addr; //一般用这个(使用网络字节顺序存)
}S_un;
} IN_ADDR;
IP地址处理:
inet_addr(): –将IP地址从点数格式转换成无符号长整型,函数返回的地址已是网络字节格式, 如:
sockaddr_in ina;
ina.sin_addr.s_addr = inet_addr(“132.241.5.10”);//与调用函数htonl()功能一样,
//代码没有错误检查,当inet_addr()发生错误时返回-1。(无符号数)-1和IP地址255.255.255.255相符合!这是广播地址!所以要先进行错误检查
ina.sin_addr.s_addr = inet_addr(“192.168.0.1”); //是将一个点分制的IP地址(如192.168.0.1)转换为ina.sin_addr.s_addr结构中需要的32位IP地址(0xC0A80001)。
inet_ntoa():–将IP地址从长整型转换成点数格式, 如:
inet_ntoa(ina.sin_addr));
它将输出IP地址。需要注意的是inet_ntoa()将结构体in-addr作为一个参数,不是长整形。
同样需要注意的是它返回的是一个指向一个字符的指针。它是一个由inet_ntoa()控制的静态的固定的指针,所以每次调用 inet_ntoa(),它就将覆盖上次调用时所得的IP地址
BSD网络编程中包含了两个函数,用来在二进制地址格式和点分十进制字符串格式之间相互转换,这两个函数仅仅支持IPv4:
in_addr_t inet_addr(const char *cp);
//将网络地址转成二进制的数字
unsigned long int inet_addr(const char *cp); //将参数cp所指的网络地址字符串转换成网络所使用的二进制数字
//将网络地址转成二进制的数字
int inet_aton(const char* cp, struct in_addr *inp); //将参数cp所指的网络地址字符串转换成网络使用的二进制的数字,然后存于参数inp所指的in_addr结构中
//将二进制的数字转换成网络地址
char* inet_ntoa(struct in_addr in); //将参数in所指的网络二进制的数字转换成网络地址,然后将指向此网络地址字符串的指针返回
功能相似的两个函数(但可同时支持IPv4和IPv6):
const char *inet_ntop(int domain, const void *addr, char *str, socklen_t size);
int inet_pton(int domain, const char *str, void *addr);
如:
char IPdotdec[20]; //存放点分十进制IP地址
192.168.0.1
struct in_addr s; // IPv4地址结构体
inet_pton(AF_INET, IPdotdec, (void *)&s); //
inet_ntop(AF_INET, (void *)&s, IPdotdec, 16);
字节的网络顺序和主机顺序:
网络字节顺序与本地字节顺序之间的转换函数
htonl()--"Host to Network Long int" 32Bytes
ntohl()--"Network to Host Long int" 32Bytes
htons()--"Host to Network Short int" 16Bytes
ntohs()--"Network to Host Short int" 16Bytes
计算机数据表示存在两种字节顺序:
网络字节顺序NBO(Network Byte Order):
按从高到低的顺序存储,在网络上使用统一的网络字节顺序,可以避免兼容性问题。
主机字节顺序(HBO,Host Byte Order):
不同的机器HBO不相同,与CPU设计有关,数据的顺序是由cpu决定的,而与操作系统无关, 如:
//将32位主机字符顺序转换成网络字符顺序
unsigned long int htonl(unsigned long int hostlong);//将参数指定的32位hostlong转换成网络字符顺序
//将16位主机字符顺序转换成网络字符顺序
unsigned short int htons(unsigned short int hostshort);//将参数指定的16位hostshort转换成网络字符顺序
一般的用法为:
程序员把类型、ip地址、端口填充sockaddr_in结构体,然后强制转换成sockaddr作为参数传递给系统调用函数
网络编程中一段典型的代码为:
int sockfd;
struct sockaddr_in servaddr;
sockfd = Socket(AF_INET, SOCK_STREAM, 0);
// 填充struct sockaddr_in
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(SERV_PORT);
inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr);
// 强制转换成struct sockaddr
connect(sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr));