Windows网络编程学习笔记(2) IPV4地址协议编程

本章将介绍IPV4地址协议编程.

SOCKADDR_IN结构体

Winsock中,将IP地址和端口号指定到sockaddr_in数据结构中:
typedef struct sockaddr_in {
SHORT sin_family;    //使用IP地址族时需要指定为AF_INET
USHORT 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;    //端口号,这里随意指定为5150
InternetAddr.sin_family=AF_INET;    //使用IP地址族时需要指定为AF_INET
InternetAddr.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来写一个通讯了.

你可能感兴趣的:(编程,C++,windows,网络,winsock)