Linux网络编程之IPv6

1.IPv6特点

我们已经学习过了流式套接字(SOCK_STREAM),数据报套接字(SOCK_DGRAM)和原始套接字(SOCK_RAWM),其中原始套接字的功能十分强大,能够传送自定义的数据包,侦听网络上的数据,拒绝服务攻击,发送ICMP包等等。但这些协议都是基于IPv4,接下来,我们学习一下IPV6下的套接字编程. 下面介绍一个IPV6协议。相对于IPv4,IPv6有如下一些显著的优势:

(1)地址容量大大扩展,由原来的32位扩充到128位,彻底解决IPv4地址不足的问题;支持分层地址结构,从而更易于寻址;扩展支持组播和任意播地址,这使得数据包可以发送给任何一个或一组节点;

(2)大容量的地址空间能够真正的实现无状态地址自动配置,使IPv6终端能够快速连接到网络上,无需人工配置,实现了真正的即插即用;

(3)报头格式大大简化,从而有效减少路由器或交换机对报头的处理开销,这对设计硬件报头处理的路由器或交换机十分有利;

(4)加强了对扩展报头和选项部分的支持,这除了让转发更为有效外,还对将来网络加载新的应用提供了充分的支持;

(5)流标签的使用让我们可以为数据包所属类型提供个性化的网络服务,并有效保障相关业务的服务质量;

(6)认证与私密性:IPv6把IPSec作为必备协议,保证了网络层端到端通信的完整性和机密性;

(7)IPv6在移动网络和实时通信方面有很多改进。特别地,不像IPv4,IPv6具备强大的自动配置能力从而简化了移动主机和局域网的系统管理。

2. IPv6地址类型

                在RFC1884中指出了三种类型的IPv6地址,他们分别占用不同的地址空间:

               * 单点传送:这种类型的地址是单个接口的地址。发送到一个单点传送地址的信息包只会送到地址为这个地址的接口。

              * 任意点传送:这种类型的地址是一组接口的地址,发送到一个任意点传送地址的信息包只会发送到这组地址中的一个(根据路由距离的远近来选择)

              * 多点传送:这种类型的地址是一组接口的地址,发送到一个多点传送地址的信息包会发送到属于这个组的全部接口。

其中单播地址又包括:全局可聚集的单播地址,站点本地地址和链路本地地址。
3  IPv6地址表示:

            对于128位的IPv6地址,考虑到IPv6地址的长度是原来的四倍,RFC1884规定的标准语法建议把IPv6地址的128位(16个字节)写成8个16位的无符号整数,每个整数用四个十六进制位表示,这些数之间用冒号(:)分开,例如:3ffe:3201:1401:1:280:c8ff:fe4d:db39

希望手工管理IPv6地址的难度太大了,DHCP和DNS的必要性在这里显得更加明显。为了简化IPv6的地址表示,只要保证数值不变,就可以将前面的0省略。

比如:1080:0000:0000:0000:0008:0800:200C:417A

可以简写为:1080:0:0:0:8:800:200C:417A

另外,还规定可以用符号::表示一系列的0。那么上面的地址又可以简化为:1080::8:800:200C:417A

IPv6地址的前缀(FP, Format Prefix)的表示和IPv4地址前缀在CIDR中的表示方法类似。比如 0020:0250:f002::/48表示一个前缀为48位的网络地址空间。

         注意: 0:0:0:0:0:0:0:1 称为本地回环地址

         链路本地地址:同一链路的相邻节点的通信,链路本地地址用于邻居发现

        站点本地地址:在企业内部可以使用的地址,相当于私网地址.

        IPv6没有广播,它的功能正在被多播代替.

        IPv4兼容地址: ::a.b.c.d 兼容a.b.c.d.

 4. IPv6地址分配

        RFC1881规定,IPv6地址空间的管理必须符合Internet团体的利益,必须是通过一个中心权威机构来分配。目前这个权威机构就是IANA(Internet Assigned NumbersAuthority,Internet分配号码权威机构)。 IANA会根据IAB(Internet ArchitectureBoard)和IEGS的建议来进行IPv6地址的分配。

目前IANA已经委派以下三个地方组织来执行IPv6地址分配的任务:

       * 欧洲的RIPE-NCC(www.ripe.net)

      * 北美的INTERNIC(www.internic.net)

     * 亚太平洋地区的APNIC(www.apnic.net)

5. IPv6地址结构

struct sockaddr_in6{
 u_char sin6_len;
 u_char sin6_family;//协议族
 u_int16_t sin6_port;//端口号
 u_int32_t sin6_flowinfo;//设置流标记
  struct in6_addr sin6_addr;//地址
 u_int32_t sin6_scope_id;//设置IPv6地址作用范围,是可聚集的全球化地址,还是本地站地址,还是链路地址

}
struct in6_addr{
 u_int8_t __u6_addr8[16];
}

in6addr_any表示本地任意地址.


6. IPv6客户端与服务器程序

服务器:

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <sys/wait.h>
#include <arpa/inet.h>
/**
IPv6服务器端与客户端设计
IPv6的地址结构
struct sockaddr_in6{
 u_char sin6_len;
 u_char sin6_family;//协议族
 u_int16_t sin6_port;//端口号
 u_int32_t sin6_flowinfo;//设置流标记
  struct in6_addr sin6_addr;//地址
 u_int32_t sin6_scope_id;//设置IPv6地址作用范围,是可聚集的全球化地址,还是本地站地址,还是链路地址

}
struct in6_addr{
 u_int8_t __u6_addr8[16];
}
**/
#define PORT 8888
#define BACKLOG 10
int main(int argc,char*argv[]){
  int s;//服务器套接字描述符
  int sc;//用于客户端通信的套接字描述符
  int ret;
  int size;
 struct sockaddr_in6 server_addr,client_addr;
  int len=sizeof(struct sockaddr_in6);
//建立套接字描述符
 s=socket(AF_INET6,SOCK_STREAM,0);  
 if(s==-1){
    perror("socket error");
   return -1;
 }
//绑定
 bzero(&server_addr,sizeof(server_addr));
 server_addr.sin6_family=AF_INET6;
 server_addr.sin6_port=htons(PORT);
 server_addr.sin6_addr=in6addr_any;//IPv6任意地址
 ret=bind(s,(struct sockaddr*)&server_addr,sizeof(server_addr));
if(ret==-1){
   perror("bind error");
  return -1;
}
//监听
ret=listen(s,BACKLOG);
if(ret==-1){
   perror("listen error");
    return -1;
 }
char buffer[1024];
//循环服务器
while(1){
  time_t now;
 
  sc=accept(s,(struct sockaddr*)&client_addr,&len);
  if(sc==-1){
    perror("accept error");
       return -1;
 }
 memset(buffer,0,1024);
 inet_ntop(AF_INET6,&client_addr.sin6_addr,buffer,sizeof(buffer));
 
 printf("a client from IP:%s,port %d,socket %d\n",buffer,client_addr.sin6_port,sc);
memset(buffer,0,sizeof(buffer));
 size=recv(sc,buffer,1024,0);
if(size>0&&!strncmp(buffer,"TIME",4)){
 now=time(NULL);
 memset(buffer,0,sizeof(buffer));
 sprintf(buffer,"%24s\r\n",ctime(&now));
 send(sc,buffer,strlen(buffer),0);

}
close(sc);
}

close(s);

}

客户端:

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <sys/wait.h>
#include <arpa/inet.h>
#define PORT 8888
#define BUFFERSIZE 1024
int main(int argc,char*argv[]){
 int s;
 int ret;
 int size;
 char buffer[BUFFERSIZE];
 struct sockaddr_in6 server_addr;
 struct sockaddr_in6 client_addr;
//建立套接字
s=socket(AF_INET6,SOCK_STREAM,0);
 if(s<0){
   perror("socket error");
   return -1;
 }
//将地址结构绑定到套接字
 bzero(&server_addr,sizeof(server_addr));
 server_addr.sin6_family=AF_INET6;
 server_addr.sin6_port=htons(PORT);
 server_addr.sin6_addr=in6addr_any;//任意地址
//连接
 ret=connect(s,(struct sockaddr*)&server_addr,sizeof(server_addr));
//发送请求
 memset(buffer,0,sizeof(buffer));
 strcpy(buffer,"TIME");
 size=send(s,buffer,strlen(buffer),0);
 if(size<=0){
   perror("send error");
   return -1;
 }
bzero(buffer,sizeof(buffer));
size=recv(s,buffer,BUFFERSIZE,0);
if(size>0){
    write(1,buffer,size);
 }
close(s);//关闭套接字描述符
}


运行结果:

./ipv6c

Sun Feb 19 20:21:31 2012

总结:本文主要介绍了IPv6特点以及与IPv4的不同点,最后给出了IPv6服务器与客户端的实例.

猜你喜欢

转载自blog.csdn.net/chenjin_zhong/article/details/7272966