第三章 网际协议
3.1 IPv4
3.1.1 寻址
3.1.1.1 单播
分配到单个计算机接口上的地址称为单播地址。该地址仅可以分配到一个接口上,如果网络上其他计算机也配置了该地址,就会发生错误,导致数据的错误传输。A,B,C三类地址组成IPv4的单播地址空间。
一般说来,为主机上的接口分配IPv4(单播)地址时,要么静态地配置,要么由配置协议分配。
3.1.1.2 多播
多播地址未被分配到某个特定接口。相反,多个计算机可以“加入”一个多播组,监听某个特定的多播地址。加入该组的每个计算机都将收到发往该多播地址的任何数据。多播地址是D类地址。多播最大的一个好处是,能将多播数据仅传送到对该数据感兴趣的那些计算机。
3.1.1.3 广播
3.1.2 IPv4管理协议
3.1.3 Winsock中的IPv4寻址
在Winsock中,应用程序通过SOCKADDR_IN结构来指定IPv4地址和服务端口信息,该结构定义为:
struct sockaddr_in
{
short sin_family;
u_short sin_port;
struct in_addr sin_addr;
char sin_zero[8];
};
3.2 IPv6
3.2.1 寻址
3.2.1.1 单播
单播地址表示单个接口。然而,对于IPv6而言,一个接口往往分配有多个单播地址。一般会遇到下列4种单播地址:
链接---本地地址
站点---本地地址
全球地址
兼容地址
3.2.1.2 任播
任播是标识多接口的地址。使用这些地址的目的,是将指向一个任播地址的数据包路由到最近的分配有该地址的接口。
3.2.1.3 多播
IPv6中的多播和IPv4中的类似。只要进程在某个特定接口加入多播组,就可收到发往该多播地址的数据。
3.2.2 IPv6管理协议
3.2.3 Winsock中的IPv6寻址
struct sockaddr_in6{
short sin6_family; //地址族AF_INET6
u_short sin6_port; //端口号
u_long sin6_flowinfo; //用于为连接标记通信量
struct in6_addr sin6_addr; //一个包含了二进制IPv6地址的16字节结构
u_long sin6_scope_id; //指明地址所在的接口索引
};
3.3 地址及名称解析
3.3.1 名称解析例程
int getaddrinfo(
const char FAR *nodename, //指定以空字符结束的主机名和文字地址
const char FAR *servname, //是一个包含端口号或服务名的以空字符结束的字符串
const struct addrinfo FAR *hints,
struct addrinfo FAR *FAR *res //返回addrINFO结构的一个链表,该结构包含了由字符串名称解析而来的地址
);
int getnameinfo(
const struct sockaddr FAR *sa, //套接字地址结构,名称信息将从这个参数中获取
socklen_t salen,
char FAR *host, //接收主机名称的字符缓冲区,默认状态下返回FQDN
DWORD hostlen,
char FAR *serv, //接收服务(或端口)信息的字符缓冲区
DWORD servlen,
int flags //指明将如何解析套接字地址
);
3.3.2 简单的地址转换
INT WSAStringToAddress(
LPTSTR AddressString, //需要转换的字符串
INT AddressFamily, //指明该字符串所属的地址族
LPWSAPROTOCOL_INFO lpProtocolInfo,
LPSOCKADDR lpAddress,
LPINT lpAddressLength
);
INT WSAAddressToString(
LPSOCKADDR lpsaAddress,
DWORD dwAddressLength,
LPWSAPROTOCOL_INFO lpProtocolInfo,
LPTSTR lpszAddressString,
LPDWORD lpdwAddressStringLength
);
3.3.3 传统名称解析例程
struct hostent FAR *gethostbyname(
const char FAR *name
);
HANDLE WSAAsyncGetHostByName(
HWND hWnd,
unsigned int wMsg,
const char FAR *name,
char FAR *buf,
int buflen
);
struct HOSTENT FAR *gethostbyaddr(
const char FAR *addr,
int len,
int type
);
HANDLE WSAAsyncGetHostByAddr(
HWND hWnd,
unsigned int wMsg,
const char FAR *addr,
int len,
int type,
char FAR *buf,
int buflen
)
getservbyname() , WSAAsyncGetServByName() , getservbyport() , WSAAsyncGetServByPort()
getprotbyname() , WSAAsyncGetProtoByName() , getprotobynumber() , WSAAsyncGetProtoByNumber()
3.4 编写独立于IP版本的程序
3.4.1 客户机
1.使用getaddrinfo函数解析地址。hints结构不仅要包含套接字类型和协议,还应该包含AF_UNSPEC。这取决于客户机是使用TCP通信,还是使用UDP通信。
2.使用步骤1返回的addrINFO结构中的ai_family , ai_socktype 和 ai_protocol字段来创建套接字。
3.使用addrINFO结构中的成员ai_addr来调用connect函数或sendto函数。
3.4.2 服务器
1.用hints结构调用getaddrinfo函数,该结构包含AI_PASSIVE , AF_UNSPEC , 所需的套接字类型,协议及所需的本地端口(这个端口用来监听或接收数据)。这个调用将返回两个addrINFO结构:一个包含用于IPv4的监听地址,另一个包含用于IPv6的监听地址。
2.针对每个返回的addrINFO结构,创建一个包含ai_family , ai_socktype 和 ai_protocol字段的套接字,接着使用ai_addr和ai_addrlen成员调用函数bind。