第07章IPv4和IPv6编程

合集下载

IPv的地址类型和编码规则

IPv的地址类型和编码规则

IPv的地址类型和编码规则IPv是Internet Protocol的缩写,是互联网上使用的一种网络协议。

它定义了计算机在互联网上进行通信时所使用的地址类型和编码规则。

本文将介绍IPv的地址类型以及相关的编码规则。

一、IPv4地址类型和编码规则IPv4(Internet Protocol version 4)是互联网上广泛采用的一种网络协议版本,它采用32位的地址长度,共分为四个8位组(也称为四个字节)。

IPv4地址的编码规则如下:1. 地址类型:IPv4地址分为公网地址和私有地址。

公网地址用于在互联网上进行通信,而私有地址则用于内部网络中的通信。

IPv4私有地址范围为10.0.0.0至10.255.255.255、172.16.0.0至172.31.255.255、192.168.0.0至192.168.255.255。

2. 地址分配:IPv4地址的分配由互联网号码分配机构(IANA)负责。

根据地址的需求和分配原则,全球的地址资源被分配给各个地区的注册局,再由注册局将地址块分配给网络服务提供商、企业或机构。

3. 地址转换:由于IPv4地址数量有限,为了解决地址短缺问题,采用了地址转换技术。

其中最常见的是网络地址转换(NAT),通过在内部网络和公网之间转换IP地址,实现多个设备共享一个公网IP地址。

4. 地址格式:IPv4地址通常以点分十进制表示法表示,如192.168.0.1。

每个八位组可以表示0~255之间的十进制数,共计2^32(约42亿)个地址。

二、IPv6地址类型和编码规则IPv6(Internet Protocol version 6)是IPv4的下一代网络协议版本,采用128位的地址长度,相比IPv4,IPv6拥有更多的地址空间。

IPv6地址的编码规则如下:1. 地址类型:IPv6地址分为单播地址、多播地址和任播地址。

单播地址用于一对一的通信,多播地址用于一对多的通信,任播地址用于一对多的通信,但只选择最近的一个节点进行通信。

v4兼容地址和IPv6隧道使用

v4兼容地址和IPv6隧道使用

使用 IPv4 兼容地址使用 IPv4 兼容地址派生自 IPv4 公用地址的 IPv4 兼容地址可以为通过现有 IPv4 Internet 结构连接 IPv6 主机或站点提供一种方法。

使用 IPv4 兼容地址时,IPv6 通信不要求其他的 IPv6 路由器。

将用 IPv4 标头封装它的通信。

下图显示了使用 IPv4 兼容地址跨 IPv4 路由器通信的独立子网上两个节点的配置。

启用兼容 IPv4 的 IPv6 地址时,Windows Server 2003 家族和 Windows XP 的IPv6 协议会将兼容 IPv4 的地址自动配置为“自动隧道伪接口(接口 ID 2)”上的 IPv4 公用地址。

IPv4 兼容地址的格式是 ::w.x.y.z,其中w.x.y.z是一个指派给计算机上接口的 IPv4 公用地址。

启用 IPv4 兼容地址时,IPv6 协议也自动创建一个 ::/96 路由,该路由使用“自动隧道伪接口”(接口 ID 为 2)转发所有 IPv4 兼容地址通信。

由此主机转发到 IPv4 兼容目标的所有通信都将用 IPv4 标头封装。

默认情况下,禁用 IPv4 兼容地址。

要启用兼容 IPv4 的地址,请打开“命令提示符”,然后键入:netsh interface ipv6 set state v4compat=enabled将通信发送到 IPv4 兼容地址时,将从 IPv4 兼容地址发送通信,并用 IPv4 标头封装。

IPv4 标头中的“协议”字段将被设置为 41,表示负载是 IPv6 数据包。

IPv4 标头允许跨 IPv4 结构进行通信。

嵌入在 IPv6 标头的源和目标 IPv4 兼容地址中的 IPv4 地址,将成为 IPv4 标头中的 IPv4 源和目标地址。

例如,当主机 A(用 IPv4 地址 131.107.41.17 配置)使用 IPv4 兼容地址将IPv6 通信发送给主机 B(用 IPv4 地址 157.60.15.93 配置)时,用于 IPv4 和IPv6 标头的源地址和目标地址在下表中列示。

IPV4与IPV6兼容socket编程接口详解

IPV4与IPV6兼容socket编程接口详解

IPV4与IPV6 兼容的socket编程套接字Socket可以看成在两个程序进行通讯连接中的一个端点,一个程序将一段信息写入Socket中,该Socket将这段信息发送给另外一个Socket中,使这段信息能传送到其他程序中。

生成套接字,主要有3个参数:通信目的IP地址、使用的协议,使用的端口号。

通过将这3个参数结合起来,应用层就可以和传输层(或网络层)通过套接字接口,区分来自不同应用程序进程或网络连接的通信。

Socket通讯流程图:TCP编程的服务器端一般步骤是:1、创建一个socket,用函数socket();2、设置socket属性,用函数setsockopt(); * 可选3、绑定IP地址、端口等信息到socket上,用函数bind();4、开启监听,用函数listen();5、接收客户端上来的连接,用函数accept();6、收发数据,用函数send()和recv(),或者read()和write(); 之后close(clientsocket);7、关闭网络连接; close(socket)TCP编程的客户端一般步骤是:1、创建一个socket,用函数socket();2、设置socket属性,用函数setsockopt();* 可选3、绑定IP地址、端口等信息到socket上,用函数bind();* 可选4、设置要连接的对方的IP地址和端口等属性;5、连接服务器,用函数connect();6、收发数据,用函数send()和recv(),或者read()和write();7、关闭网络连接;UDP编程的服务器端一般步骤是:1、创建一个socket,用函数socket();2、设置socket属性,用函数setsockopt();* 可选3、绑定IP地址、端口等信息到socket上,用函数bind();不需要listen()4、数据交互,用函数recvfrom(); sendto()5、关闭网络连接;UDP编程的客户端一般步骤是:1、创建一个socket,用函数socket();2、设置socket属性,用函数setsockopt();* 可选3、绑定IP地址、端口等信息到socket上,用函数bind();* 可选4、设置对方的IP地址和端口等属性;函数connect();* 可选5、数据交互,用函数sendto(); recvfrom();如果调用了connect就直接可以用send和recv了,这时最后两个参数会自动用connect建立时的地址信息填充6、关闭网络连接;几个Socket 地址结构相关结构体注:在操作系统(内核)不同情况下,首两个字节可能是length+family#ifdef ISC_PLATFORM_HA VESALENntp_u_int8_t ss_len; /* address length */ntp_u_int8_t ss_family; /* address family */#elseshort ss_family; /* address family */#endifstruct in_addr {u_int32_t s_addr; /* 4bytes, IPv4 address */};=4struct in6_addr {u_int8_t s6_addr[16]; /* IPv6 address */}=16一般socket函数都是传入的这个类型指针struct sockaddr {sa_family_t sa_family; /* unsigned short address family, AF_xxx */ char sa_data[14]; /* 14 bytes of protocol address */};2+14=16struct sockaddr_in {short int sin_family; /* Address family */unsigned short int sin_port; /* Port number */struct in_addr sin_addr; /* Internet address */unsigned char sin_zero[8]; /* Same size as struct sockaddr */};2+2+4+8=16struct sockaddr_in6{sa_family_t sin6_family; //地址簇类型,为AF_INET6in_port_t sin6_port; //16 位端口号,网络字节序uint32_t sin6_flowinfo; //32 位流标签struct in6_addr sin6_addr; //128 位IP 地址/*uint32_t sin6_scope_id;*/(新版本可能会多4字节scope id, RFC2553)}2+2+4+16=24#define UNIX_PATH_MAX 108struct sockaddr_un {sa_family_t sun_family; /* AF_UNIX,本地进程通讯*/char sun_path[UNIX_PATH_MAX]; /* pathname */};=110例:my_addr.sun_family = AF_UNIX;strncpy(my_addr.sun_path, MY_SOCK_PATH, sizeof(my_addr.sun_path) - 1);sockaddr_storage能提供严格的结构对齐sockaddr_storage能容纳系统支持的更大的地址结构,容器在使用sockaddr_storage定义的变量时,尽量强制转换成struct sockaddr, struct sockaddr_in, struct sockaddr_in6后操作struct __kernel_sockaddr_storage {unsigned short ss_family; /* address family *//* Following field(s) are implementation specific */char __data[_K_SS_MAXSIZE - sizeof(unsigned short)];/* space to achieve desired size, *//* _SS_MAXSIZE value minus size of ss_family */} __attribute__ ((aligned(_K_SS_ALIGNSIZE))); /* force desired alignment */#define sockaddr_storage __kernel_sockaddr_storage=128不同于sockaddr_storag的一个IPV4,IPV6兼容结构体(来源于busybox)typedef struct len_and_sockaddr {socklen_t len;union {struct sockaddr sa;struct sockaddr_in sin;struct sockaddr_in6 sin6;};} len_and_sockaddr;用struct sockaddr_storage的好处,看:取得res后声明一个struct sockaddr_storage变量以兼容IPV4和IPV6 //….getaddrinfo后建立socketstruct sockaddr_storage local_addr;memset(&local_addr, 0, sizeof(struct sockaddr_storage));if(res->ai_family == AF_INET6){struct sockaddr_in6 *local_addr6 = (struct sockaddr_in6 *)&local_addr;local_addr6->sin6_family = AF_INET6;local_addr6->sin6_port = htons(udp_local_port);local_addr6->sin6_addr = in6addr_any;}else if(res->ai_family == AF_INET){struct sockaddr_in *local_addr4 = (struct sockaddr_in *)&local_addr;local_addr4->sin_family = AF_INET;local_addr4->sin_port = htons(udp_local_port);local_addr4->sin_addr.s_addr = htonl(INADDR_ANY);}if(bind(usd, (struct sockaddr *)&local_addr, sizeof(local_addr)) == -1){perror("bind");fprintf(stderr, "could not bind to local udp port %d\n", udp_local_port);exit(1);}freeaddrinfo(res);//….send recv等数据交互一些重要函数主机字节序到网络字节序间的转换函数uint16_t htons(uint16_t hostshort);uint16_t ntohs(uint16_t netshort);uint32_t htonl(uint32_t hostlong);uint32_t ntohl(uint32_t netlong);例:本机字节序与网络字节序short int port=0x1234; //本地存储, windows为小端系统,所以存34 12 sockaddr_in.sin_port = htons(port); //网络传输,TCP包头里的数据顺序IPV4字符串地址和网络序ip地址的转换函数int inet_aton(const char *cp, struct in_addr *inp);char *inet_ntoa(struct in_addr in);in_addr_t inet_addr(const char *cp);IPV6,IPV4兼容的字符串地址和网络序ip地址的转换函数int inet_pton(int af, const char *src, void *dst);const char *inet_ntop(int af, const void *src, char *dst, socklen_t cnt);两个地址长度的宏#define INET_ADDRSTRLEN 16#define INET6_ADDRSTRLEN 46IPV4主机名和地址的转换struct hostent *gethostbyname(const char *name);struct hostent *gethostbyaddr(const void *addr, socklen_t len, int type);IPV6,IPV4兼容的主机名和地址的转换函数struct hostent *gethostbyname2(const char *name, int af); //扩展版本,也支持IPV6int getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res);void freeaddrinfo(struct addrinfo *res); //调用时机:在bind或connect之后就可以释放该内存int getnameinfo(const struct sockaddr *sa, socklen_t salen, char *host, size_t hostlen, char *serv, size_t servlen, int flags);getaddrinfo函数原型addrinfo结构首先了解下:1.通配地址IPV4:0.0.0.0IPV6:::stat指令查询监听,绑定等的IP和port信息作为服务器端时:struct addrinfo hints, *res=NULL;memset(&hints,0,sizeof(hints));hints.ai_family=AF_UNSPEC;//hints.ai_family=AF_INET6;hints.ai_socktype=SOCK_DGRAM;//hints.ai_protocol=IPPROTO_UDP;hints.ai_flags=AI_PASSIVE;rc=getaddrinfo(NULL,"123",&hints,&res);socket=socket(res->ai_family,res->ai_socktype,res->ai_protocol);bind (socket,res->ai_addr,res->ai_addrlen);hints可看作是过滤条件res返回一个地址链表,一般来说用第一个bind成功就可以了可以看到sa_addr的sa_data在端口后面是全0的,相当于是通配地址因此其相当于下面不调用getaddrinfo方法的简化版本:usd = socket(AF_INET6, SOCK_DGRAM, 0);struct sockaddr_storage local_addr;memset(&local_addr, 0, sizeof(struct sockaddr_storage));struct sockaddr_in6 *local_addr6 = (struct sockaddr_in6 *)&local_addr;local_addr6->sin6_family = AF_INET6;local_addr6->sin6_port = htons(123);local_addr6->sin6_addr = in6addr_any;if(bind(usd, (struct sockaddr *)&local_addr, sizeof(local_addr)) == -1)……提示:用IPV6建立服务器端的话, 即使客户端仍用IPV4的socket连接也可以正常通讯, IPV4的地址会被转换成这种地址::ffff:192.168.27.25而旧的IPV4时用以下代码:usd = socket(AF_INET, SOCK_DGRAM, 0);struct sockaddr_in servaddr;bzero(&servaddr,sizeof(servaddr));servaddr.sin_family = AF_INET;servaddr.sin_port = htons(123);servaddr.sin_addr.s_addr = htons(INADDR_ANY);if (bind(servfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) == -1)……服务器端从IPV4移植到IPV6要做些什么?可以调用getaddrinfo得到AF_INET6的通配地址,也可以直接将sockaddr_in结构体更改为sockaddr_in6结构体并相应初始化即可客户器端如何同时兼容IPV4和IPV6?按如上方法就可同时兼容IPV4和IPV6的连接请求作为客户器端时:memset(&hints,0,sizeof(hints));hints.ai_family=AF_UNSPEC;hints.ai_socktype=SOCK_DGRAM;//hints.ai_protocol=IPPROTO_UDP;hints.ai_flags=AI_CANONNAME;rc=getaddrinfo("","ntp",&hints,&res);socketfd=socket(res->ai_family,res->ai_socktype,res->ai_protocol);connect(sockfd,res->ai_addr , res->ai_addrlen);如图res返回两个ai_addr,一个sa_family是0x2为AF_INET,另一个为0x17 AF_INET6;说明该主机既有AAAA(或A6)记录(IPV6)地址,同时又有A记录(IPV4)地址,那么AAAA 记录将作为sockaddr_in6结构返回,而A记录则作为sockaddr_in结构返回dig AAAA 客户器端从IPV4移植到IPV6要做些什么?如果服务器端具有IPV4地址则基本不需改动,因为IPV6的服务器对IPV4客户端是兼容的,如果是域名且是IPV6的地址则必须调用getaddrinfo得到addrinfo的可用IP地址。

IPV4和IPV6地址ppt课件

IPV4和IPV6地址ppt课件

7、如果第二个位等于 1,则向总数增加 2。
8、如果第一个位等于 1,则向总数增加 1。
精选课件ppt
4
二进制转化十进制
将8 位二进制数 10111001转换为十进制数: 1、第八个位等于 1,向总数增加 128。总数现在是 128。 2、第六个位等于 1,向总数增加 32。总数现在是 160。 3、第五个位等于 1,向总数增加 16。总数现在是 176。 4、第四个位等于 1。向总数增加 8。总数现在是 184。 5、第一个位等于 1。向总数增加 1。总数现在是 185。 或表示为:27+25+24+23+20=185 这样,二进制数 10111001 就是十进制数 185。
网络号:172.16.64.0
10101100 00010000 01010000 01100100
逻辑与
11111111 11111111 11000000 00000000 结果
10101100 00010000 01000000 00000000
精选课件ppt
26
目录
➢二进制与十进制的互相转换 ➢ 有类别IPV4地址 ➢ IP地址相关计算
精选课件ppt
9
IPv4地址结构
IPv4的IP地址包括两个部分:NETID和HOSTID,
NETID标识一个网络. HOSTID标识在该网络上的一个主机。
IP地址格式:NetID + HostID
网络标识(NetID):表示主机所在网络; 主机标识(HostID):表示主机在网段中的唯一标识。
NET ID
HostID
精选课件ppt
10
网络ID位
IPv4 A类地址
主机ID位
A 类网络 ID 被分配给拥有大量主机的网络。

ipv4与ipv6兼容socket编程

ipv4与ipv6兼容socket编程

ipv4与ipv6兼容socket编程//客户端代码#include#include#include#include#include#include#include#include#include#include#include#include#include#include#include#include#includeint main(int argc,char *argv[]){struct addrinfo *ailist,*aip;struct addrinfo hint;struct sockaddr_in6 *sinp;int sockfd;int err;int i=0;char seraddr[INET_ADDRSTRLEN];short serport;char msg[200];int len;if(argc !=2){printf("usage:%s \n",argv[0]);exit(-1);}hint.ai_family=0;hint.ai_socktype=SOCK_DGRAM;hint.ai_flags=AI_CANONNAME;hint.ai_protocol=0;hint.ai_addrlen=0;hint.ai_addr=NULL;hint.ai_canonname=NULL;hint.ai_next=NULL;if((err=getaddrinfo(argv[1],"8888",&hint,&ailist))!=0){printf("getaddrinfo error: %s\n",gai_strerror(err));exit(-1);}printf("getaddrinfo ok\n");for(aip=ailist;aip!=NULL;aip=aip->ai_next){sinp=(struct sockaddr_in6 *)aip->ai_addr;if(inet_ntop(sinp->sin6_family,&sinp->sin6_addr,seraddr,INE T_ADDRSTRLEN)!=NULL){printf("server address is %s \n",seraddr);}serport=ntohs(sinp->sin6_port);printf("server port is %d \n",serport);if((sockfd=socket(aip->ai_family,SOCK_DGRAM,0))<0){printf("create socket failed : %s\n",strerror(errno));}printf("create socket ok \n");while(1){bzero(msg,sizeof(msg));len=read(STDIN_FILENO,msg,sizeof(msg));if(sendto(sockfd,msg,sizeof(msg),0,aip->ai_addr,aip->ai_add rlen)<0){printf("error");exit(1);}if((len=recvfrom(sockfd,msg,sizeof(msg),0,aip->ai_addr,&ai p->ai_addrlen))<0){perror("recvfrom error");exit(1);};printf("%d:",i);i++;printf("Received message : %s\n",msg);}}exit(0);}//服务器端代码#include#include#include#include#include#include#include#include#include#include#include#include#include#includeint main(int argc,char *argv[]){if(argc !=2){printf("参数格式错误!正确的格式是:\n\t\t%s 端口\t 比如:\t%s 80 \n",argv[0],argv[0]);}struct addrinfo hints,*res,*ressave;char msg[200];char buf[300];size_t addrlen;bzero(&hints,sizeof(struct addrinfo)); res=NULL;ressave=NULL;hints.ai_flags=AI_PASSIVE;hints.ai_family=0;hints.ai_socktype=SOCK_DGRAM; hints.ai_protocol=IPPROTO_UDP; hints.ai_addrlen=0;hints.ai_addr=NULL;hints.ai_canonname=NULL;hints.ai_next=NULL;int err;int i=0;int len;int addr_len;if((err=getaddrinfo(NULL,argv[1],&hints,&res))!=0) {perror("getaddrinfo error");exit(1);}ressave=res;int mySock;if(!res){printf("res is NULL\n");}struct sockaddr_storage addr;bzero(&addr,sizeof(addr));while(res){mySock=socket(res->ai_family,res->ai_socktype,res->ai_pro tocol);if(mySock<0){perror("sock error");continue;}const int on=1;setsockopt(mySock,SOL_SOCKET,SO_REUSEADDR,&on,sizeo f(on));if(bind(mySock,res->ai_addr,res->ai_addrlen)==0){printf("bind success \n");break;}else{perror("bind error");}close(mySock);res=res->ai_next;}if(!res){printf("failed to get a address for service \n");}addr_len=sizeof(struct sockaddr_storage);while(1){bzero(msg,sizeof(msg));printf("it is recving !\n");len=recvfrom(mySock,msg,sizeof(msg),0,ressave->ai_addr, &ressave->ai_addrlen);printf("%d:",i);printf("addr->sa_family:%d",ressave->ai_family);printf("%s\n",msg);i++;if(sendto(mySock,msg,len,0,ressave->ai_addr,ressave->ai_a ddrlen)<0){perror("error");exit(1);}}}。

LINUX IPV6 IPV4 兼容编程 HTTP SERVER 源代码讲解

LINUX IPV6 IPV4 兼容编程 HTTP SERVER 源代码讲解

LINUX IPV6 IPV4 兼容编程 HTTP SERVER 源代码讲解代码是在linux上运行的,winsock的已经有人写了IPv4转换示例192.168.0.77c:::ffff:192.168.0.77。

打印后,删除::ffff:以获取IPv4地址有些函数比如debug_printf什么的我就不贴了,太多了看不过来,重点看红色标注部分intmain(){intlistenfd=-1,connectfd;pthread_utthread;//idofthreadstructarg*arg;//passthisvartothethreadcharbuf[bufsize];chartemp[bufsize];调试打印(\intport=80;调试打印(\memset(temp,0x0,bufsize);sprintf(temp,\//配置地址信息structaddrinfoaddrcriteria;memset(&addrcriteria,0,sizeof(addrcriteria));addrcriteria。

ai_uufamily=af_uuuunsec;addrcriteria。

ai_u标志=ai_u被动;addrcriteria.ai_socktype=sock_stream;addrcriteria.ai_protocol=ipproto_tcp;//获取地址信息。

此函数是必需的,因为接口同时具有IPv6和IPv4。

它通常位于Dr_uAnyStructAddRinfo*服务器uAddr;intretval=getaddrinfo(null,temp,&addrcriteria,&server_addr);if(retval!=0){调试打印(\}structaddrinfo*addr=server_addr;//获得的地址是一个链表。

事实上,它只是以下地址的IPv6地址:while(addr!=null){//建立套接字listenfd=socket(addr->ai_family,addr->ai_socktype,addr->ai_protocol);if(listenfd<0)continue;//绑定端口和侦听端口intopt=so_uureuseaddr;setsockopt(listenfd,sol_socket,so_reuseaddr,&opt,sizeof(opt));//可重用fcntl(listenfd,f_setfd,fd_cloexec);fcntl(列表、f_设置、o_非块);//非阻塞if((bind(listenfd,addr->ai_addr,addr->ai_addrlen)==0)&&listen(listenfd,128)==0){structsockaddr_uuStorageLocal_uuAddr;socklen_uutaddr_uusize=sizeof(本地地址);if(getsockname(listenfd,(structsockaddr*)&local_addr,&addr_size)<0){调试\uPrintf(\}debug_printf(\printsocketaddress((StructSocketAddr*)和local_uuAddr);//一般来说:break;}close(listenfd);addr=addr->ai_uuNext;}freeaddrinfo(server_addr);//事实上,以上都是胡说八道。

《IPV4和IPV6地址》课件

《IPV4和IPV6地址》课件

04
IPv4和IPv6的比较
地址空间
总结词
IPv4地址空间较小,IPv6地址空间较 大。
详细描述
IPv4使用32位地址,理论上最多有 2^32-1个地址,而IPv6使用128位地 址,理论上最多有2^128-1个地址, 大大扩展了地址空间。
路由表大小
总结词
IPv4路由表较大,IPv6路由表较小。
IPv6子网掩码
• IPv6子网掩码用于标识一个IPv6地址中的网络部分和主机部分 。IPv6子网掩码是一个128位的掩码,其中连续的1表示网络部 分,连续的0表示主机部分。例如,子网掩码为 255:255:255:255:255:255:255:255表示一个单播地址,子网 掩码为255:255:255:0表示一个多播地址或任播地址。
D类地址:用于多播。
04
05
E类地址:保留为特殊用途。
IPv4子网掩码
子网掩码用于标识IP地址中的网络部 分和主机部分。
通过子网掩码可以判断任意两个IP地 址是否属于同一子网。
子网掩码由连续的1和0组成,其中1表示 网络部分 络部分,最后一个字节为主机部分。
02
IPv6地址
IPv6地址的表示方法
冒号十六进制记法
将IPv6地址分为8组,每组由四个 十六进制数字组成,组之间用冒 号分隔。例如: 2001:0db8:85a3:0000:0000:8a2 e:0370:7334。
压缩记法
在IPv6地址中,如果连续的零组 可以被省略,但前提是省略后不 会引起歧义。例如: 2001:0db8:85a3:8a2e:0370:733 4可以简写为 2001:0db8:85a3:8a2e:370:7334 。
03

IP-IPv4-IPv6

IP-IPv4-IPv6

3.IP掩码的标注
A、无子网的标注法
对无子网的IP地址,可写成主机号为0的掩码。如IP地址210.73.140.5,掩码为255.255.255.0,也可以缺省掩码,只写IP地址。
B、有子网的标注法
有子网时,一定要二者配对出现。以C类地址为例。
1.IP地址中的前3个字节表示网络号,后一个字节既表明子网号,又说明主机号,还说明两个IP地址是否属于一个网段。如果属于同一网络区间,这两个地址间的信息交换就不通过路由器。如果不属同一网络区间,也就是子网号不同,两个地址的信息交换就要通过路由器进行。例如:对于IP地址为210.73.140.5的主机来说,其主机标识为00000101,对于IP地址为210.73.140.16的主机来说它的主机标识为00010000,以上两个主机标识的前面三位全是000,说明这两个IP地址在同一个网络区域中,这两台主机在交换信息时不需要通过路由器进行10.73.60.1的主机标识为00000001,210.73.60.252的主机标识为11111100,这两个主机标识的前面三位000与011不同,说明二者在不同的网络区域,要交换信息需要通过路由器。其子网上主机号各为1和252。
3.C类IP地址
一个C类IP地址是指,在IP地址的四段号码中,前三段号码为网络号码,剩下的一段号码为本地计算机的号码。如果用二进制表示IP地址的话,C类IP地址就由3字节的网络地址和1字节主机地址组成,网络地址的最高位必须是“110”。C类IP地址中网络的标识长度为21位,主机标识的长度为8位,C类网络地址数量较多,适用于小规模的局域网络,每个网络最多只能包含254台计算机。
网关
大家都知道,从一个房间走到另一个房间,必然要经过一扇门。同样,从一个网络向另一个网络发送信息,也必须经过一道“关口”,这道关口就是网关。顾名思义,网关(Gateway)就是一个网络连接到另一个网络的“关口”。
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

源代码的可移植性
• 将gethostbuname()和gethostbyaddr()调用删 除,转而使用getaddrinfo()和getnameinfo() 函数。
• 假设进程创建了一个IPv4的监听套接口,然 后接收到一个来自IPv4客户的连接。该服务 器调用fork和exec,启动一个新程序处理客 户请求。这个过程同以前介绍的并发服务 器的唯一不同是将已连接套接口复制到事 先约定的描述字,然后调用exec。但被加载 的新程序期望一个这是IPv6套接口,而不是 IPv4套接口,因此可以用IPv6_ADDBFORM套 接口选项来转换该套接口的地址格式,如 下:
• 下面来看当一个双重协议栈主机接收到数 据时的处理,根据接收套接口的类型(TCP 或UDP)对一个收到的IPv4或IPv6 数据报进 行如图7-2所示的处理。
IPv6客户与IPv4服务器
• (1)如果IPv4的TCP客户调用connect时或IPv4的UDP客户调用 sendto时指定的是一个IPv4地址,不需要作任何特殊处理。 • (2)如果IPv6的TCP客户调用connect时或IPv6的UDP客户调用 sendto时指定的是一个IPv6地址,不需要作任何特殊处理。 • (3)如果IPv6的TCP客户调用connect时或IPv6的UDP客户调用 sendto时指定的是一个IPv4映射的IPv6地址,内核会检测到这个 映射地址,并发送一个IPv4数据报,而不是IPv6数据报。 • (4)IPv4客户不能在为在IPv4的sockaddr_in结构里的4字节的in_addr结构中放不下 一个16字节的IPv6地址。 • 通过以上处理,也可以使IPv6客户与IPv4服务器通信,这就达到 了从IPv4过渡到IPv6的目的。
IPv6_ADDRFORM套接口选项
• 为什么要学习IPv6_ADDRFORM套接口选项 呢?这得从它的功能说起, IPv6_ADDRFORM套接口选项能把一个套接 口从一种类型转变成另一种类型。那为什 么要转变地址格式呢?目的是在UNIX上文 件描述字可以在进程之间进行传递,而最 通常传递的方式就是通过fork来实现。
• 1. int af; • 2. socklen_t clilen; • 3. struct sockaddr_in6 cli; /*IPv6 struct*/ • 4. struct hostent *ptr; • • 5. af = AF_INET6; • 6. Setsockopt(STDIN_FILENO,IPPROTO_IPV6,IPV6_AD DRFORM,&af,sizeof(af)); • • 7. clilen = sizeof(cli); • 8. Getpeername(0,&cli,&clilen);
第7章 IPv4和IPv6编程
• • • • 知识点: IPv4和IPv6服务器的工作原理 IPv6如何为IPv4客户端服务 IPv6地址测试宏与IPv6套接口选项
IPv4客户与IPv6服务器
• 拥有双重协议栈的主机的一个基本持性是: 其上运行的IPv6服务器既能应付IPv4客户, 又能应付IPv6客户。这是通过使用IPv4映射 的IPv6地址实现的。
• 对于一个IPv6的UDP服务器来说,情形是类 似的,只需将每个数据报改变一次地址格 式。例如一个IPv6服务器收到从IPv4客户发 来的数据报,于是由recvfrom返回的地址将 是该客户对IPv4映射的IPv6地址。同时服务 器用这个映射的地址调用sendto对客户的请 求作出响应。若是IPv6客户,则地址为IPv6 地址,而不是映射后的地址。在此UDP服务 器问题得到解决。
int IN6_IS_ADDR_MC_NODELOCAL (const struct in6_addr *aptr); int IN6_IS_ADDR_MC_LINKLOCAL (const struct in6_addr *aptr); int IN6_IS_ADDR_MC_SITELOCAL (const struct in6_addr *aptr); int IN6_IS_ADDR_MC_ORGLOCAL (const struct in6_addr *aptr); int IN6_IS_ADDR_MC_GLOBAL (const struct in6_addr *aptr); 返回值:若非零表示IPv6地址是指定类型的,否则返回0。
• 如果用IPv6_ADDRFORM作参数来调用 getsockopt,返回值依赖于套接口地址的格 式,将为AF_INET或AF_INET6。getsockopt和 setsockopt的第二个参数可以是IPPROTO_IP 或IPPROTO_IPV6。
IPv6地址测试宏
• • • • • • • • • • • • • • • • • 为测试IPv6地址的某些持性我们定义了总共12个宏来达到这个目的,如下: #include <netinet/in.h> int IN6_IS_ADDR_UNSPECIFIED (const struct in6_addr *aptr); int IN6_IS_ADDR_LOOPBACK (const struct in6_addr *aptr); int IN6_IS_ADDR_MULTICAST (const struct in6_addr *aptr); int IN6_IS_ADDR_LINKLOCAL (const struct in6_addr *aptr); int IN6_IS_ADDR_SITELOCAL (const struct in6_addr *aptr); int IN6_IS_ADDR_V4MAPPED (const struct in6_addr *aptr); int IN6_IS_ADDR_V4COMPAT (const struct in6_addr *aptr);

• IPv4 TCP客户与一个IPv6服务器之间讲行通信的步骤。 • (1)启动IPv6服务器,创建一个IPv6的监听套接口,我们假定该套接 口绑定了通配地址。 • (2)IPv4客户调用gethostbyname找到一个与该服务器对应的A记录。 因为这台服务器主机同时支持IPv4和IPv6,所以它应该既有一个A记录, 又有一个AAAA记录,但IPv4的客户只需要一个A记录。 • (3)客户进程调用connect,客户主机向服务器发送一个IPv4的SYN。 • (4)服务器主机收到这个发往IPv6监听套接口的IPv4 SYN,置一个标 志,表明这个连接使用IPv4映射的IPv6地址,然后响应一个IPv4的 SYN/ACK。当这个连接建立后,accept返回给服务器的地址就是这个 IPv4映射的IPv6地址。 • (5)在客户和服务器之间的所有通信使用IPv4数据报。 • (6)除非服务器明确地去检查这个IPv6地址是不是一个IPv4映射的 IPv6地址(使用IN6_IS_ADDR_V4MAPPKD宏),它将不会知道通信的 对方是一个IPv4客户。双重协议栈屏蔽了这个细节。同样,IPv4的客 户也不知道与之通信的是一个IPv6的服务器。
相关文档
最新文档