一.因为 Winsock 要兼容多个协议,所以必须使用通用的寻址方式。
TCP/IP使用IP地址和端口号指定一个地址
winsock第一版使用的sockaddr 结构
struct sockaddr
{
u_short sa_family;
char sa_data[14];
};
在这个结构中,
第一个成员sa_family 指定了这个地址使用的地址家族。
sa_data 成员存储的数据在不同的地址家族中可能不同。
sockaddr 结构的TCP/IP 版本——sockaddr_in 结构
struct sockaddr_in
{
short sin_family; // 地址家族(即指定地址格式),应为AF_INET
u_short sin_port; // 端口号
struct in_addr sin_addr; // IP 地址
char sin_zero[8]; // 空字节,要设为0
};
(1)sin_family 域必须设为AF_INET,它告诉Winsock 程序使用的是IP 地址家族。
(2)sin_port 域指定了TCP 或UDP 通信服务的端口号。应用程序在选择端口号时必须小
心,因为有一些端口号是保留给公共服务使用的,如FTP 和HTTP。
基本上,端口号可分成
如下3 个范围:公共的、注册的、动态的(或私有的)。
?? 0~1 023 由IANA(Internet Assigned Numbers Authority)管理,保留为公共的服务使用。
?? 1 024~49 151 是普通用户注册的端口号,由IANA 列出。
?? 49 152~65 535 是动态和/或私有的端口号。
普通用户应用程序应该选择 1024~49151之间的注册了的端口号,以避免使用了一个其
他应用程序或者系统服务已经使用的端口号。在49 152~65 535 之间的端口号也可以*地
使用,因为没有服务注册这些端口号。
(3)sin_addr 域用来存储IP 地址(32 位),它被定义为一个联合来处理整个32 位的值,
两个16 位部分或者每个字节单独分开。
描述32 位IP 地址的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_addr S_un.S_addr /* can be used for most tcp & ip code */
#define s_host S_un.S_un_b.s_b2 // host on imp
#define s_net S_un.S_un_b.s_b1 // network
#define s_imp S_un.S_un_w.s_w2 // imp
#define s_impno S_un.S_un_b.s_b4 // imp #
#define s_lh S_un.S_un_b.s_b3 // logical host
} IN_ADDR, *PIN_ADDR, FAR *LPIN_ADDR;
用字符串“aa.bb.cc.dd”表示IP 地址时,字符串中由点分开的4 个域是以字符串的形式
对in_addr 结构中的4 个u_char 值的描述。由于每个字节的数值范围是0~255,所以各域的
值都不可超过255。
(4)最后一个域sin_zero 没有使用,是为了与SOCKADDR 结构大小相同才设置的。
// 将一个"aa.bb.cc.dd"类型的IP 地址字符串转化为32 位的二进制数
unsigned long inet_addr(const char* cp);
// 将32 位的二进制数转化为字符串
char * inet_ntoa (struct in_addr in);
二。字节顺序
TCP/IP 统一规定使用大尾方式传输数据,也称为网络字节顺序。例如,端口号(它是一
个16 位的数字)12345(0x3039)的存储顺序是0x30、0x39。32 位的IP 地址也是以这种方
式存储的,IP 地址的4 部分存储在4 个字节中,第一部分存储在第一个字节中。
上述 sockaddr 和sockaddr_in 结构中,除了sin_family 成员(它不是协议的一部分)外,
其他所有值必须以网络字节顺序存储。
Winsock 提供了一些函数来处理本地机器的字节顺序和网络字节顺序的转换:
u_short htons(u_short hostshort); // 将u_short 类型变量从主机字节顺序转化到TCP/IP 网络字节顺序
u_long htonl(u_long hostlong); // 将u_long 类型变量从主机字节顺序转化到TCP/IP 网络字节顺序
u_short ntohs(u_short netshort); // 将u_short 类型变量从TCP/IP 网络字节顺序转化到主机字节顺序
u_long ntohl(u_long netlong); // 将u_long 类型变量从TCP/IP 网络字节顺序转化到主机字节顺序