struct sockaddr {
ushortsa_family;//地址族,如AF_INET,2字节
charsa_data[14];//存放地址和端口,14字节
};
Sockaddr是通用的地址结构,因为winsock不单支持TCP/IP,还有很多其他协议。
除了sin*_family参数,sockaddr的内容都是以网络字节序存储的。
sockaddr_in是TCP/IP协议专用的地址结构
struct sockaddr_in{
shortsin_family;//地址族,必须为AF_INET
u_short sin_port;//端口号,如果设为0,则windows自动在1024-5000之间为应用
//程序分配一个端口号。如果要指定端口号,记得使用htons将主
//机字节序转为网络字节序
structin_addr sin_addr;
charsin_zero[8];//8字节数组,全为0。因为上面sin_family和sin_port各占2
//字节,下面会看到sin_addr占4字节,为了使sockaddr_in和//sockaddr大小一样(16字节),所以加上8字节填充。
};
typedef structin_addr
{
union {
struct {
u_char s_b1,s_b2,s_b3,s_b4;
} S_un_b;
struct {
u_short s_w1,s_w2;
} S_un_w;
u_long S_addr;
} S_un;
} IN_ADDR,*PIN_ADDR,FAR *LPIN_ADDR;
这里使用联合类型非常巧妙,使得程序员设置IP时有多种选择。对于IP地址211.69.198.216,有下面三种赋值方法:
sin_addr.S_un.S_un_b.s_b1=211;
sin_addr.S_un.S_un_b.s_b2=69;
sin_addr.S_un.S_un_b.s_b3=198;
sin_addr.S_un.S_un_b.s_b4=216;
sin_addr.S_un.S_un_w.s_w1=(69<<8)|211;
sin_addr.S_un.S_un_w.s_w1=(216<<8)|198;
注:这里是存为两个2字节的unsigned short,在每一个short里都要按照主机字节序来存放。经过上面的移位和按位或运算,从S_un_w中又可以按顺序读取出211 69 198 216了。(s_w1中69在高字节,211在低字节,那么存在内存中就是211在低地址,69在高地址)参见网络字节序和主机字节序
sin_addr.S_un.S_addr=inet_addr(“211.69.198.216”);
inet_addr将字符串形式的IP地址转换为unsigned long形式
同时还要注意,实际代码中in_addr的定义里还定义了一些别名,在c:Program FilesMicrosoftSDKsWindowsv6.0AIncludeinaddr.h中in_addr是这样定义的:
typedef struct in_addr{
union {
struct { UCHAR s_b1,s_b2,s_b3,s_b4; } S_un_b;
struct { USHORT s_w1,s_w2; } S_un_w;
ULONG S_addr;
} S_un;
#define s_addrS_un.S_addr
#define s_hostS_un.S_un_b.s_b2// host on imp
#define s_netS_un.S_un_b.s_b1// network
#define s_impS_un.S_un_w.s_w2// imp
#define s_impnoS_un.S_un_b.s_b4// imp #
#define s_lhS_un.S_un_b.s_b3// logical host
} IN_ADDR, *PIN_ADDR, FAR*LPIN_ADDR;
因此我们也经常可以见到sin_addr.s_addr这样的写法,其实和sin_addr.S_un.S_addr是等价的。