C++中的IPv6网络措施设计
当前位置:以往代写 > C/C++ 教程 >C++中的IPv6网络措施设计
2019-06-13

C++中的IPv6网络措施设计

C++中的IPv6网络措施设计

副标题#e#

IPv4最初是由美国国防部开拓的用于网际互联(IP)协议,厥后它不只成长了TCP,并且还进一步成长了IPv4(IP协议4.0版)。IPv4此刻已经遍及应用于Internet网络中,同时也应用于大大都计较机系统,局域网和广域网中。然而,跟着Internet中的计较机数量突飞猛涨,IPv4的范围性加倍现显:

1.IPv4地点数目面对耗尽,日近告急;

2.IPv4寻址并非完全分品级,这使得Internet关节路由器必需维持大量的路由表,承担过重。

3.IPv4的地点必需被静态分派或通过设置协议(如:DHCP)举办分派。IPv6的开拓方针之一就是将提供更为轻便的设置方案。

于是IPv6(6.0版本)应运而生。在Window系统中,Windows XP 提供了IPv6的developer-release版本;Windows 2000也可在http://www.microsoft.com/ipv6 下载 IPv6协议预览。下图在本人计较机上乐成安装的示例图:

图-1 IPV6 安装示例

一.IPv4地点及其寻址

1.IPv4地点

IPv4地点(常称IP地点)用一个32位数暗示;凡是暗示位十进制名目,地点的每8位字节被暗示转为一个十进制的数值,并由句点脱离,如:192.168.0.1;IPv4地点 凡是分为A、B、C、D、E 五类。

2.IPv4寻址

在Winsock 中,通过SOCKADDR_IN 布局来指定IPv4的地点和处事断口信息:

struct sockaddr_in {

short sin_family ;//必需为AF_INET,暗示利用IPv4地点簇

u_short sin_port; //TCP/UDP 端口

struct in_addr sin_addr;// IP地点(以网络字节顺序分列, 4个字节)

char sin_zero[8];//填充项

}   

二.IPv6地点及其寻址

1.IPv6地点

IPv6地点与IPv4地点的显著的差异是128位,长度是IPv4地点的4倍。IPv6地点由16位字节分段暗示,显示为冒号脱离的十六进制:

21DA:00D3:0000:2F3A:B234:ED12:9C5A:DAC3

IPv6地点的分派

分派

地点前缀

保存地点0000 0000

为NSAP预留0000 0001

可聚合的全球单播地点001

链接-当地单播地点1111 1110 10

站点-当地单播地点1111 1110 11

多播地点1111 1111

2.IPv6的寻址

Winsock中,寻址利用一下布局:

struct  sockaddr_in6{
short sin6_family;// 地点簇:AF_INET6
u_short sin6_port;//端标语
u_long sin6_flowinfo;//毗连标志通信量
struct in6_addr sin6_addr;//16字节布局的IPv6 地点
u_long sin6_scope_id;//地点所有的接口索引

}


#p#副标题#e#

三.独立于协议的地点及名称理会 

由此可见在寻址时,IPv4利用16字节的SOCK_ADDR_IN 布局,IPv6则利用28 字节的SOCK_ADDR_IN6 布局。为了办理这个问题,IPv6中引入了新的寻址函数。 [Page]

1.getaddrinfo(),它提供独立于协议的名称理会:

int getaddrinfo(
 const char *FAR *nodename,
 const  char FAR* servname,
 const struct addrinfo FAR *hins,
 struct addrinfo FAR *FAR *res 
);

l 第一参数:nodename,以空字节竣事的主机名或文字地点

l 第二参数:servname,包括端口或处事名(如:FTP,TELNET)的以空字节竣事的字符串

l 第三个参数:hins 是一个布局(addrinfo),包括名称理会的执行方法选项

l 第四个参数:res ,用于返回 addrinfo 布局的一个或多个链表

布局addrinfo 的界说:

struct    addrinfo{
int ai_flags;
int ai_family;
int ai_socktype;
int ai_protocol ;
size_t ai_addrlen;
char *ai_cannoname;
struct sockaddr *ai_addr;
struct addrinfo *ai_next;
}

l ai_flags 选值:AI_PASSIVE:可以用来获取可以或许通报给bind函数的地点,此时nodename应配置为NULl ,servname为欲绑定的端口;AI _CANONNAME 暗示nodename 是主机名;AI_NUMBERICHOST 暗示, nodename 是一个文字字符串地点(如:“192.168.0.1”)

l ai_family 选值:AI_INET或PF_INET(IPv4地点簇);AI_INET6或PF_INET6(IPv6地点簇);AI_UNSPEC(未指定,大概是IPv4或IPv6 地点簇)

l ai_socktype选值:SOCK_DGRAM(UDP范例套接字);SOCK_STREAM (TCP类  型套接字)

l ai_protocol 选值:IPPROTO_TCP (TCP/IP协议)

假如函数理会乐成,理会后的地点将通过res返回。假如名称被理会为多个地点,则返回一个由ai_next 字段形成的链表。每个由名称理会的地点在ai_addr中暗示,长度在ai_addrlen中暗示。

2.getnameinfo()函数与getaddrinfo()相对应,成果相反。

.      int getnameinfo(
                const struct sockaddr FAR *sa,
                socklen_t salen, [Page]
                char FAR *host,
              DWORD hostlen,
              char FAR *serv,
              DWORD servlen,
              Int flags);

以上参数的寄义较量明明,不再一一说明。

3.释放函数:freeaddrinfo(res);

#p#副标题#e#

四、兼容IPv4和IPv6的网络措施设计

兼容IPv4和IPv6的网络措施,显然涉及到两个部门:客户机和处事器。

在Windows 网络编程中,Winsock是一种尺度的API(应用措施接口),Winsock2版本已经成长成独立于协议的的接口,被遍及应用于Windows平台中。

<一>客户机措施设计

#p#分页标题#e#

对付客户机来说,不管是成立TCP/UDP 毗连,它都应知道处事器的主机名或IP 地点,同时将处事器地点理会为IPv4或IPv6地点都可以,一般可以思量一下步调:

SOCKET s;
struct addrinfo,hints,*res=NULl ;
char *szRemoteAddress;//主机名或IP 地点
char *szRemotePort;//端标语
int rc;

1.用getaddrinfo() 函数理会地点。hins布局中 利用AF_UNSPEC符号,便可以得到地点簇范例(IPv4或IPv6)。

memset(&hintas,0,sizeof(hints));
hints.ai_family=AF_UNSPEC;
hints.ai_socktype=SOCK_STREAM;
hints.ai_protocol =IPPROTO_TCP;
rc=getaddrinfo(szRemoteAdddress,szRemotePort,&hints,&res);
if(rc==WSANO_DATA)
{// 无法理会,堕落 
}

用返回的addrinfo布局中的ai_family,ai_socketype,ai_protocol字段来建设套接字。

s=socket(res->ai_family,ai_socktype,res->protocol );
if(s==INVALID_SOCKET)
{//建设套接字失败 
}

2.利用返回的addrinfo布局中的ai_addr来挪用其他函数(connect(),send()等).。

rc==connect(s,res->ai_addr,res->addrlen);
if(rc==SOCKET_ERROR)
{//毗连失败;
}
。。。//完成其他编程

<二>处事器措施设计

处事器措施设计,应思量到IPv4和IPv6 都具有各自的仓库;因此假如处事器但愿能同时接管IPv4和IPv6的毗连,就必需能同时建设IPv4和IPv6套接字;一般可以思量一下步调:

SOCKET socklisten[2];//监听Socket变量
char *szPort=”8080”;//监听端口
struct addinfo hints,*res=NULl ,*ptr=NULl ;
int rc,i=0;

1.  挪用getaddrinfo()函数,该布局包括AI_PASSIVE,AF_UNSPEC符号,以及所需的套接字范例、协议及所需的当地端口(用来监听和接管数据等)。函数将返回的两个addrinfo布局,别离可用于IPv4和IPv6监听地点:[Page]

memset(&hints,0,sizeof(hints));
hints.ai_family=AF_UNSPEC;
hints.ai_socktype=SOCK_STREAM;
hints.ai_protocol =IPPROTO_TCP;
hints.ai_flags=AI_PASSIVE;
rc=getaddinfo(NULl ,szPort,&hints,&res);
if(rc!=0){//失败处理惩罚;}
ptr=res;

2. 用返回的addrinfo布局中的ai_family,ai_socketype,ai_protocol字段来建设套接字后;便可以利用addrinfo布局中的ai_addr 和ar_addrlen 字段挪用绑定函数bind()。

while(ptr)
{
socklisten[i]=socket(ptr->ai_family,ptr->ai_socktype,ptr->ai_protocol );
if(socklisten[i]==INVALID_SOCKET){//建设失败处理惩罚;}
rc=bind(socklisten[i],ptr->ai_addr,ptr->ai_addrlen);
if(rc==SOCKET_ERROR){//绑定失败处理惩罚}
rc=listen(slisten[i],7)//开始监听
if(rc==SOCKET_ERROR){//监听失败处理惩罚}
i++;
ptr=ptr->ai_next;
}
     。。。
//完成其他编程

#p#副标题#e#

五、措施实例

在这里,给出一个基于IPV6的简朴回应(ECHO)处事器措施.

1.成立CIPv6类

// IPv6.h: 头文件,这里利用到了套接字中的“select I/O模子”

#define WIN32_LEAN_AND_MEAN    
#include <winsock2.h>
#include <ws2tcpip.h>
#include <tpipv6.h>    //IPv6 头文件
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#pragma comment(lib, "ws2_32.lib")//套接字库文件
#define DEFAULT_PORT "7274" // 默认端口
#define BUFFER_SIZE   64   // 数据缓冲区

class CIPv6
{
public:
 // 建设TCP 处事器
 int CreateServer(char *Port = DEFAULT_PORT,char *Address = NULl );
 void Usage(char *ProgName);//用户信息提示
 LPSTR DecodeError(int ErrorCode);//获取错误信息
 CIPv6();
 virtual ~CIPv6();

};

// IPv61.cpp: CIPv6类的实现 .
// IPv61.cpp: implementation of the CIPv6 class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "IPv61.h"

int CIPv6::CreateServer(char *Port, char *Address)
{
 char Buffer[BUFFER_SIZE], Hostname[NI_MAXHOST];
 int RetVal , FromLen, AmountRead;
 SOCKADDR_STORAGE From;
 WSADATA wsaData;
 ADDRINFO Hints, *AddrInfo;
 SOCKET ServSock;
 fd_set SockSet;
 // 启动Winsock
 if ((RetVal = WSAStartup(MAKEWORD(2, 2), &wsaData)) != 0)
 {
  fprintf(stderr, "WSAStartup failed with error %d: %s\n",
   RetVal , DecodeError(RetVal ));
  WSACleanup();
  return -1;
 }
 if (Port == NULl )
 {
  Usage("Port Error");
 }
 memset(&Hints, 0, sizeof(Hints));
 Hints.ai_family =AF_INET6;// Family;
 Hints.ai_socktype =SOCK_STREAM;
 Hints.ai_flags = AI_NUMERICHOST | AI_PASSIVE;
 RetVal = getaddrinfo(Address, Port, &Hints, &AddrInfo);
 if (RetVal != 0)
 {
  fprintf(stderr, "getaddrinfo failed with error %d: %s\n", RetVal , gai_strerror(RetVal ));
  WSACleanup();
  return -1;
 }
 // 建设套接字
 ServSock = socket(AddrInfo->ai_family,AddrInfo->ai_socktype, AddrInfo->ai_protocol );
 if (ServSock == INVALID_SOCKET)
 {
  fprintf(stderr, "socket() failed with error %d: %s\n",
   WSAGetLastError(), DecodeError(WSAGetLastError()));
   WSACleanup();
   return -1;
 }
 // 绑定套接字
 if (bind(ServSock, AddrInfo->ai_addr, AddrInfo->ai_addrlen) == SOCKET_ERROR)
 {
  fprintf(stderr,"bind() failed with error %d: %s\n",
   WSAGetLastError(), DecodeError(WSAGetLastError()));
  WSACleanup();
  return -1;
 }
 // 侦听
 if (listen(ServSock, 5) == SOCKET_ERROR)
 {
  fprintf(stderr, "listen() failed with error %d: %s\n",
   WSAGetLastError(), DecodeError(WSAGetLastError()));
  WSACleanup();
  return -1;
 }
 printf("'Listening' on port %s, protocol %s, protocol family %s\n",
  Port, \"TCP\",
  "PF_INET6");

 freeaddrinfo(AddrInfo);
 //利用select I/O 模子举办收发
 FD_ZERO(&SockSet);
 while(1)
 {
  FromLen = sizeof(From);
  if (FD_ISSET(ServSock, &SockSet)) break;
  FD_SET(ServSock, &SockSet);
  if (select(0, &SockSet, 0, 0, 0) == SOCKET_ERROR)
  {
   fprintf(stderr, "select() failed with error %d: %s\n",
    WSAGetLastError(), DecodeError(WSAGetLastError()));
   WSACleanup();
   return -1;
  }
 }
 if (FD_ISSET(ServSock, &SockSet))
 {
  FD_CLR(ServSock, &SockSet);
 }
 //接管一个毗连
 SOCKET ConnSock;
 ConnSock = accept(ServSock, (LPSOCKADDR)&From, &FromLen);
 if (ConnSock == INVALID_SOCKET)
 {
  fprintf(stderr, "accept() failed with error %d: %s\n",
   WSAGetLastError(), DecodeError(WSAGetLastError()));
   WSACleanup();
   return -1;
 }
 if (getnameinfo((LPSOCKADDR)&From, FromLen, Hostname,
  sizeof(Hostname), NULl , 0, NI_NUMERICHOST) != 0)
  strcpy(Hostname, "<unknown>");
  printf("\nAccepted connection from %s\n", Hostname);
  while(1)
  {
   //期待接管数据
   AmountRead = recv(ConnSock, Buffer, sizeof(Buffer), 0);
   if (AmountRead == SOCKET_ERROR)
   {
    fprintf(stderr, "recv() failed with error %d: %s\n", WSAGetLastError(), DecodeError(WSAGetLastError()));
     closesocket(ConnSock);
    break;
   }
   if (AmountRead == 0) {
    printf("Client closed connection\n");
     closesocket(ConnSock);
    break;
   }

   printf("Received %d bytes from client: [%.*s]\n",
    AmountRead, AmountRead, Buffer);
   //举办简朴ECHO 回应
   printf("Echoing same data back to client\n");
    RetVal = send(ConnSock, Buffer, AmountRead, 0);
   if (RetVal == SOCKET_ERROR)
   {
    fprintf(stderr, "send() failed: error %d: %s\n",
     WSAGetLastError(), DecodeError(WSAGetLastError()));
    closesocket(ConnSock);
    break;
   }
  }
  return 0;
}

void CIPv6::Usage(char *ProgName)
{
 fprintf(stderr, "\nSimple socket sample server program.\n");
  fprintf(stderr, "transport tEither TCP or UDP. (default: %s)\n",
  "TCP");
  fprintf(stderr, "port\t\tPort on which to bind. (default %s)\n",
  DEFAULT_PORT);
 fprintf(stderr, "address\tIP address on which to bind.(default: unspecified address)\n");
  WSACleanup();
 exit(1);
}

LPSTR CIPv6::DecodeError(int ErrorCode)
{
 static char Message[1024];
 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS |
  FORMAT_MESSAGE_MAX_WIDTH_MASK, NULl , ErrorCode,
  MAKELANGID(LANG_NEUTRAl , SUBLANG_DEFAULT),
  (LPSTR)Message, 1024, NULl );
 return Message;
}

2.应用示例

#p#分页标题#e#

#include "stdafx.h"
#include "IPv6.h"
int main(int argc, char* argv[])
{
 CIPv6 m_ipv6;
 m_ipv6.CreateServer(); //回收默认建设处事器,
 //假如你乐成安装了IPv6可以利用正常利用
 return 0;
}

    关键字:

在线提交作业