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

更新时间:2023-10-25 17:39:01 阅读量: 综合文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

在网上看了很多资料,要不是长篇大论讲原理,要不就是直接贴代码,连个说明都没有,都不知道函数是干嘛的,下面这个代码直接就可以用,在一个同时有IPV4和IPV6地址的接口上,跑一个HTTP服务,这个兼容编程的办法实际上可以看出是把IPV4的地址转成了IPV6的地址

代码是在LINUX上运行的,WINSOCK的已经有人写了

IPV4转换范例 192.168.0.77 –》 ::ffff:192.168.0.77 ,将它打印出来以后去掉::ffff:就可以得到IPV4地址了

有些函数比如debug_printf什么的我就不贴了,太多了看不过来,重点看红色标注部分

int main() {

int listenfd=-1, connectfd;

pthread_t thread; //id of thread

struct ARG *arg; //pass this var to the thread char buf[BUFSIZE]; char temp[BUFSIZE];

debug_printf(\

int port=80;

debug_printf(\

memset(temp,0x0,BUFSIZE); sprintf(temp,\

//配置地址信息

struct addrinfo addrCriteria;

memset(&addrCriteria,0,sizeof(addrCriteria)); addrCriteria.ai_family=AF_UNSPEC; addrCriteria.ai_flags=AI_PASSIVE;

addrCriteria.ai_socktype=SOCK_STREAM; addrCriteria.ai_protocol=IPPROTO_TCP;

//获取地址信息,因为接口既有IPV6又有IPV4所以需要这个函数,一般都是inaddr_any struct addrinfo *server_addr;

int retVal=getaddrinfo(NULL,temp ,&addrCriteria,&server_addr); if(retVal!=0) {

debug_printf(\

}

struct addrinfo *addr=server_addr; //获取的地址是一个链表,实际上一般只是::的IPV6地址

while(addr!=NULL) {

//建立socket

listenfd=socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol); if(listenfd<0) continue;

//绑定端口和监听端口 int opt = SO_REUSEADDR;

setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));//可重用 fcntl(listenfd, F_SETFD, FD_CLOEXEC);

fcntl(listenfd, F_SETFL, O_NONBLOCK);//非阻塞

if((bind(listenfd,addr->ai_addr,addr->ai_addrlen)==0)&& listen(listenfd,128)==0) {

struct sockaddr_storage local_addr; socklen_t addr_size=sizeof(local_addr);

if(getsockname(listenfd,(struct sockaddr *)&local_addr,&addr_size)<0) {

debug_printf(\ }

debug_printf(\

PrintSocketAddress((struct sockaddr*)&local_addr); //一般是:: break; }

close(listenfd);

addr=addr->ai_next; }

freeaddrinfo(server_addr);

//其实上面都是废话,对于IPV4来说,inaddr_any就是0.0.0.0,对IPV6来说就是:: //但标准代码得这么写

if(listenfd<0) {

debug_printf(\ return ERROR; }

while(1) //MAIN LOOP {

//debug_printf(\

struct sockaddr_storage client_addr; //struct sockaddr_storage可以兼容IPV4 IPV6 socklen_t client_addrLen=sizeof(client_addr);

if((connectfd=accept(listenfd,(struct sockaddr *)&client_addr,&client_addrLen) ) <0) {

usleep(10000); continue; }

debug_printf(\

PrintSocketAddress((struct sockaddr*)&client_addr);

arg = (struct ARG *)malloc(sizeof(struct ARG)); memset(arg,0x0,sizeof(struct ARG)); arg->connfd = connectfd;

if(pthread_create(&thread, NULL, http_routine, (void*)arg))//这里就可以直接处理HTTP了,我就不贴了 {

debug_printf(\ continue; }

pthread_detach(thread);//detach the thread for recyle }

close(listenfd); return OK; }

//这个函数可以把CLIENT的地址打出来

void PrintSocketAddress(const struct sockaddr *address) {

// Test for address and stream if (address == NULL ) return;

void *numericAddress; // Pointer to binary address // Buffer to contain result (IPv6 sufficient to hold IPv4) char addrBuffer[INET6_ADDRSTRLEN]; in_port_t port; // Port to print

// Set pointer to address based on address family switch (address->sa_family) {

case AF_INET:

numericAddress = &((struct sockaddr_in *) address)->sin_addr; port = ntohs(((struct sockaddr_in *) address)->sin_port); break;

case AF_INET6: //其实根本不会是AF_INET,因为IPV4地址也会MAP成IPV6 numericAddress = &((struct sockaddr_in6 *) address)->sin6_addr; port = ntohs(((struct sockaddr_in6 *) address)->sin6_port); break; default:

debug_printf(\ // Unhandled type return; }

// Convert binary to printable address //

if (inet_ntop(address->sa_family, numericAddress, addrBuffer,sizeof(addrBuffer)) == NULL) {

debug_printf(\ } else {

debug_printf(\将可见地址打出来

if (port != 0) // Zero not valid in any socket addr debug_printf(\ } }

一些关键的INCLUDE

#include #include #include #include #include #include

结束语,从代码可以看出关键点是getaddrinfo 和 inet_ntop ,网上讲这2个函数的很多,但都不说如何使用,这个代码换掉一些函数和参数可以直接使用,WIN7访问HTTP IPV6的话先得有IPV6地址,自己配一个比如2001::100 ,找个LINUX(地址2001::101)跑这个代码,在浏览器上输入 http://[20001::101]:80 就可以访问了

本文来源:https://www.bwwdw.com/article/r102.html

Top