您的位置:首页 > 理论基础 > 计算机网络

UNXI网络编程笔记 第12章IPV4与IPV6的互操作性

2016-09-24 12:24 260 查看
IPv4客户与IPv6服务器:

地址转换是由服务器端处理的

假设服务器支持双协议栈,而且即有一个IPv4地址,由有一个IPv6地址。服务器绑定了IPv6的通配地址。此时IPv4客户端要与服务器通信:

1)IPv6服务器启动,创建IPv6套接字,并且绑定通配地址

2)IPv4客户通过域名解析getaddrinfo找到服务器主机的IPv4地址

3)客户调用connect连接服务器IPv4地址

4)服务器收到SYN报文,根据端口发现端口是绑定到IPv6地址上面的,所以设置一个标识指示这个连接应使用IPv4映射的IPv6地址。然后正常回复SYN报文,建立连接。连接建立后,accept返回给主机进程的客户端地址就是客户端的IPv4地址映射的IPv6地址。

5)当服务器向客户发送数据时,IP栈会把目的地址设置为客户端的IPv4地址。所以链路上的数据都是IPv4承载的。

IPv6客户与IPv4服务器:

此时客户需要连接IPv4服务器的‘IPv4地址映射的IPv6地址’

客户端向这个映射到IPv6地址发消息时,IP栈检查到报文到目的地址是一个映射地址,所以会把目的地址修改为IPv4地址。

客户端的一种比较好的实现方式是,在getaddrinfo时,设置addrinfo结构的ai_flags = AI_V4MAPPED | AI_ALL,这样如果服务器只有IPv4地址,DNS会把服务器的IPv4地址映射的IPv6地址返回给客户端,客户端需要遍历返回的addrinfo结构中的地址进行连接尝试。

//tcpclientv6.c
#include "common.h"

int main(int argc, char **argv){

if(argc < 2){
puts("usage:tcpclient hostname");
return 1;
}

struct addrinfo hints,*result;
bzero(&hints,sizeof(hints));
bzero(&result,sizeof(result));
hints.ai_family = AF_INET6;
hints.ai_flags = AI_V4MAPPED | AI_ALL;

int n = getaddrinfo(argv[1],NULL,&hints,&result);
if(n != 0){
printf("getaddrinfo error:%s\n",gai_strerror(n));
return 1;
}

struct addrinfo *saveResult = result;
int needtry = 1;

while(needtry && result != NULL){
int sockfd;
char buf[100];
struct sockaddr_in6 serveraddr;
bzero(&serveraddr,sizeof(serveraddr));

serveraddr =*((struct sockaddr_in6*)(result->ai_addr));
serveraddr.sin6_port = htons(45000);

char addrbuf[200];
inet_ntop(result->ai_family,&(((struct sockaddr_in6*)(result->ai_addr))->sin6_addr.s6_addr),addrbuf,sizeof(addrbuf));
printf("try %s:%d\n",addrbuf,45000);

sockfd = socket(result->ai_family,SOCK_STREAM,0);

int rtn = connect(sockfd,(struct sockaddr*)&serveraddr,sizeof(serveraddr));
if(rtn != 0){
puts("connect error");
result = result->ai_next;
continue;
}

puts("connecetd.");
needtry = 0;

fd_set readset;
FD_ZERO(&readset);
FD_SET(sockfd,&readset);
int sockStdin = fileno(stdin);
FD_SET(fileno(stdin),&readset);

int stdineof = 0;

while (1) {
FD_SET(sockfd,&readset);
int maxfd = sockfd;
if(stdineof == 0) {
FD_SET(sockStdin,&readset);
maxfd = MAX(sockfd,fileno(stdin));
}
int nReady = select(maxfd + 1,&readset,NULL,NULL,NULL);
if(nReady > 0){
if(FD_ISSET(sockStdin,&readset)){
int readNum = read(sockStdin,buf,sizeof(buf));
if(readNum == 0){
puts("eof, close socket");
shutdown(sockfd,1);
FD_CLR(sockStdin,&readset);
stdineof = 1;
continue;

}
write(sockfd,buf,readNum);
}

if(FD_ISSET(sockfd,&readset)){
int readNum = read(sockfd,buf,sizeof(buf));
if(readNum == 0){
if(stdineof == 1) {
puts("server close socket");
return 0;
}
else err_sys("client read error");
}
write(fileno(stdout),buf,readNum);
}
}
}
}
freeaddrinfo(saveRes);
return 0;
}


//pollSvr.c
#include "common.h"
#include <poll.h>
#include <limits.h>

void sig_chld(int signo){

pid_t pid;
int stat;
//pid = wait(&stat);
while( (pid = waitpid(-1,&stat, WNOHANG)) > 0)
printf("child %d terminated\n",pid);
return;
}

int main(int argc, char **argv) {

int sockfd, clientfd;
struct sockaddr_in6 serveraddr,clientaddr;
char buf[100];
bzero(&serveraddr,sizeof(serveraddr));
bzero(&clientaddr,sizeof(clientaddr));
serveraddr.sin6_family = AF_INET6;
inet_pton(AF_INET6,"::0",&serveraddr.sin6_addr.s6_addr);
serveraddr.sin6_port = htons(45000);

sockfd = socket(AF_INET6,SOCK_STREAM,0);

bind(sockfd,(struct sockaddr*)&serveraddr,sizeof(serveraddr));

listen(sockfd,10);

Signal(SIGCHLD, sig_chld);

printf("OPEN_MAX=%d\n",OPEN_MAX);
struct pollfd client[OPEN_MAX];

int i;
for(i = 0;i<OPEN_MAX;i++){
client[i].fd = -1;
}

int maxi = 0;
client[0].fd = sockfd;
client[0].events = POLLRDNORM;

while(1){
int newMaxi = 0;
for(int i = 0; i <= maxi; i++){
if(client[i].fd != -1){
newMaxi = i;
}
}
maxi = newMaxi;
int nready = poll(client,maxi+1,-1);

for(i = 1; i <= maxi; i++){
clientfd = client[i].fd;
if(clientfd < 0) continue;

if(client[i].revents & (POLLRDNORM | POLLERR)){
int n = read(clientfd,buf,sizeof(buf));
if(n < 0){
client[i].fd = -1;
close(clientfd);
err_sys("read errof");
}

if(n == 0){
puts("client close socket");
client[i].fd = -1;
close(clientfd);
continue;
}
buf
= 0;
printf("%s",buf);
write(clientfd,buf,n);

if(--nready <= 1)
break;
}
}
if(client[0].revents & POLLRDNORM){
socklen_t len = sizeof(clientaddr);
clientfd = accept(sockfd,(struct sockaddr*)&clientaddr,&len);
if(clientfd < 0)
err_sys("connect error");

inet_ntop(AF_INET6,&clientaddr.sin6_addr.s6_addr,buf,len);
printf("new connection from:%s:%d\n",buf,ntohs(clientaddr.sin6_port));
for(i = 1;i<OPEN_MAX;i++){
if(client[i].fd == -1){
client[i].fd = clientfd;
client[i].events = POLLRDNORM;
break;
}
}

if(i == OPEN_MAX)
err_sys("too many sockets error");

maxi = MAX(i,maxi);

if(--nready <= 0)
continue;
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  网络编程