SOCKADDR_IN结构体
Winsock中,将IP地址和端口号指定到sockaddr_in数据结构中
typedef struct sockaddr_in {SHORT sin_family; // 使用IP地址族时需要指定为AF_INETUSHORT sin_port; // 端口号IN_ADDR sin_addr; // IP地址CHAR sin_zero[8]; // 用于补齐,使结构体大小与SOCKADDR相等} SOCKADDR_IN, *PSOCKADDR_IN;
另一种数据结构
typedef struct sockaddr {u_short sa_family;CHAR sa_data[14]; // 14字节的协议地址} SOCKADDR, *PSOCKADDR, FAR *LPSOCKADDR;
SOCKADDR_IN 与 SOCKADDR 的区别
SOCKADDR_IN中的sin_zero[8]用于将其大小补到与SOCKADDR相等,可以用bzero()或memset()函数将其置为零,两者可以混用,只需要在使用时用指针进行转换时即可.
指向sockaddr_in 的指针和指向sockaddr的指针可以相互转换,这意味着如果一个函数所需参数类型是sockaddr时,你可以在函数调用的时候将一个指向 sockaddr_in的指针显示转换为指向sockaddr的指针;或者相反。
你只要记住,填值的时候使用sockaddr_in结构,而作为函数的参数传入的时候转换成sockaddr结构就行了,毕竟都是16个字符长。
IP地址结构体
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#define s_net S_un.S_un_b.s_b1#define s_imp S_un.S_un_w.s_w2#define s_impno S_un.S_un_b.s_b4#define s_lh S_un.S_un_b.s_b3} IN_ADDR, *PIN_ADDR, FAR *LPIN_ADDR;
可以简单地认为该结构体是一个四字节的地址,无非是使用联合使之能够被更方便的使用.
大多数情况下使用 s_addr ,即联合中的最后一种形式来赋值.
可以使用下列函数方便地将带点的IP地址转换为4字节形式.
unsigned long inet_addr(const char FAR * cp; // 参数cp为不带结束符用点隔开的地址字符串,比如 "127.0.0.1");
字节顺序
不同机器的字节顺序不同,有大端小端两种.
大端字节序:高字节数据存放在内存低地址处,低字节数据存放在内存高地址处.
小端字节序:低字节数据存放在内存低地址处,高字节数据存放在内存高地址处.
在网络编程中,存在主机字节序(host-byte order)和 网络字节序(network-byte order).
当一个IP地址和端口号以多字节形式存在于计算机中时,它们是主机字节序.
当存在于网络中时,它们是网络字节序.
网络标准规定网络中的多字节值必须以大端字节序存在,因此需要做相应转换.
接下来的几个函数用于字节序的转换
主机字节序转换为网络字节序
u_long htonl(u_long hostlong); // unsigned long形字节转换,返回值为转换结果int WSAHtonl(SOCKET s,u_long hostlong, // 主机字节序的 4 字节数据u_long FAR *lpnetlong // 转换结果保存到lpnetlong指向的内存中);u_short htons(u_short hostshort); // unsigned short形字节转换,返回值为转换结果int WSAHtons(SOCKET s,u_short hostshort, // 主机字节序的 2 字节数据u_short FAR *lpnetshort // 转换结果保存到lpnetlong指向的内存中);
相反的,网络字节序转换为主机字节序
u_long ntohl(u_long netlong);WSANtohl(SOCKET s,u_long netlong,u_long FAR *lphostlong);u_short ntohs(u_short netshort);WSANtohs(SOCKET s,u_short netshort,u_short FAR *lphostshort);
综上,我们已经知道如何填写一个 IPV4 地址了,代码如下
SOCKADDR_IN InternetAddr; // 存放IPV4地址的数据结构INT nPortID=5150; // 端口号,这里随意指定为5150InternetAddr.sin_family=AF_INET; // 使用IP地址族时需要指定为AF_INETInternetAddr.sin_addr.s_addr=inet_addr("136.149.3.29"); // 将IP地址"136.149.3.29"转换为4字节形式InternetAddr.sin_port=htons(nPortID); // 将端口号从主机字节序转换为网络字节序,这里参数做了隐式转换int->unsigned short
一般数字形式的IP不容易记忆,因此有一系列跟IP地址获取相关的函数,这在后面将会详细介绍
现在你已经有了IPV4地址协议的基本概念,你已经可以通过创建一个socket来写一个通讯了
