转自http://blog.csdn.net/chenjin_zhong/article/details/7272966
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服务器与客户端的实例.