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结构中的地址进行连接尝试。
地址转换是由服务器端处理的
假设服务器支持双协议栈,而且即有一个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; }
相关文章推荐
- Unix网络编程学习笔记之第12章 IPv4与IPv6的互操作性
- Unix网络编程学习笔记之第12章 IPv4与IPv6的互操作性
- IPv6下网络编程socket, TCP和UDP例子,以及兼容IPV4和IPV6的类
- 网络编程中常见地址结构与转换(IPv4/IPv6)
- Beej的网络编程入门教程 第五篇 从IPv4到IPv6
- 网络编程:Socket编程从IPv4转向IPv6支持
- 网络编程之IPv4和IPv6的互通性剩余小知识点(二)
- IPv6下网络编程socket, TCP和UDP例子,以及兼容IPV4和IPV6的类
- (转)网络编程:Socket编程从IPv4转向IPv6支持
- Linux网络编程IPv4和IPv6的inet_addr、inet_aton、inet_pton等函数小结
- 网络编程中常见地址结构与转换(IPv4/IPv6)
- 网络编程之IPv4和IPv6的互通性(一)
- IPv6下网络编程socket, TCP和UDP例子,以及兼容IPV4和IPV6的类
- 网络编程学习笔记(gethostbyname2函数与IPv6支持)
- UNP函数笔记九: IPv4与IPv6的互操作性
- Linux网络编程一步一步学-IPv6下网络编程步骤
- (笔记)网络编程基础--要整理!
- Linux网络编程一步一步学-IPv6下网络编程步骤
- 传智博客学习笔记15--JAVA网络编程
- Java学习笔记(七、网络编程基础)