问答一下,轻松解决,电脑应用解决专家!
主板显卡CPU内存显示器
硬盘维修显卡维修显示器维修
注册表系统命令DOS命令Win8
存储光存储鼠标键盘
内存维修打印机维修
WinXPWin7Win10/Win11
硬件综合机箱电源散热器手机数码
主板维修CPU维修键盘鼠标维修
Word教程Excel教程PowerPointWPS
网络工具系统工具图像工具
数据库javascriptLinux系统
PHP教程CSS教程XML教程

监控IPv4和IPv6下的相同端口

更新时间:2021-09-10 13:50 作者:叨陪鲤点击:

如今,随着网络的日益普及,IPv4地址数量相对于与日俱增的网络设备而言,简直太稀缺了,已经远远无法满足日常需求,因此出现了IPv6协议,并开始逐渐向IPv6进行过渡。在如今的过渡阶段中,网络环境中同时存在IPv4网络和IPv6网络,因此开发软件时通常要求支持双栈的功能

同时监控双栈(IPv4栈、IPv6栈)下的指定端口号实现上也比较简单,分别创建两个套接字:

  • 一个用来监听IPv4端口
  • 一个用来监听IPv6端口

只是这里面有一个需要注意的地方:

创建两个UDP套接字,分别监听IPv4,IPv6端口,不存在特别的问题。但是TCP却不同,如果先创建并绑定IPv4的端口,则另一个套接字无法直接绑定IPv6的相同端口。会提示如下信息:

bind failed: : Address already in use

此时需要设置IPv6套接字的高级选项(IPPROTO_IPV6)方可以进行绑定和监听:

static const int on = 1;
setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY,(const void *)&on, sizeof(on))

UDP无需此项参数设置,具体原因未知。

完整代码实现如下(包括udp, tcp监控双栈代码):

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <string.h>

int creatSocketUdp(char *ip, short port)
{
	static const int on = 1;
	
	int fd;
	struct sockaddr_in server;
	
	if ((fd = socket(AF_INET, SOCK_DGRAM, 0))<0){
		perror("creatSocketUdp_v6 create socket failed: ");
		return -1;
	}else if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const void *)&on, sizeof(on))<0){
		perror("creatSocketUdp_v6 set REUSEADDR failed: ");
		return -1;
	}
	
	bzero(&server, sizeof(server));
	server.sin_family = AF_INET;
	server.sin_port = htons(port);
	server.sin_addr.s_addr = htonl(INADDR_ANY);

	int ret = bind(fd, (struct sockaddr *)&server, sizeof(server));
	if (ret != 0){
		perror("creatSocketUdp_v6 bind failed: ");
		return -1;
	}
	return fd;
}

int creatSocketUdp_v6(char *ip, short port)
{
	static const int on = 1;
	
	int fd;
	struct sockaddr_in6 server;
	
	if ((fd = socket(AF_INET6, SOCK_DGRAM, 0))<0){
		perror("creatSocketUdp_v6 create socket failed: ");
		return -1;
	}else if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const void *)&on, sizeof(on))<0){
		perror("creatSocketUdp_v6 set REUSEADDR failed: ");
		return -1;
/*	}else if(setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY,(const void *)&on, sizeof(on))<0){
		perror("creatSocketUdp_v6 set REUSEADDR failed: ");
		return -1; */
	}
	
	bzero(&server, sizeof(server));
	server.sin6_family = AF_INET6;
	server.sin6_addr = in6addr_any;
	server.sin6_port = htons(port);
	
	int ret = bind(fd, (struct sockaddr *)&server, sizeof(server));
	if (ret != 0){
		perror("creatSocketUdp_v6 bind failed: ");
		return -1;
	}
	return fd;
}


int creatSocketTcp(char *ip, short port)
{
	static const int on = 1;
	
	int fd;
	struct sockaddr_in server;
	
	if ((fd = socket(AF_INET, SOCK_STREAM, 0))<0){
		perror("creatSocketTcp create socket failed: ");
		return -1;
	}else if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const void *)&on, sizeof(on))<0){
		perror("creatSocketTcp set REUSEADDR failed: ");
		return -1;
	}
	
	bzero(&server, sizeof(server));
	server.sin_family = AF_INET;
	server.sin_port = htons(port);
	server.sin_addr.s_addr = htonl(INADDR_ANY);

	int ret = bind(fd, (struct sockaddr *)&server, sizeof(server));
	if (ret != 0){
		perror("creatSocketTcp bind failed: ");
		return -1;
	}
	
	if (listen(fd, 5)<0){
		perror("creatSocketTcp listen failed: ");
		return -1;
	}
	return fd;
}

int creatSocketTcp_v6(char *ip, short port)
{
	static const int on = 1;
	
	int fd;
	struct sockaddr_in6 server;
	
	if ((fd = socket(AF_INET6, SOCK_STREAM, 0))<0){
		perror("creatSocketTcp_v6 create socket failed: ");
		return -1;
	}else if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const void *)&on, sizeof(on))<0){
		perror("creatSocketTcp_v6 set REUSEADDR failed: ");
		return -1;
	}else if(setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY,(const void *)&on, sizeof(on))<0){
		perror("creatSocketTcp_v6 set REUSEADDR failed: ");
		return -1; 
	}
	
	bzero(&server, sizeof(server));
	server.sin6_family = AF_INET6;
	server.sin6_addr = in6addr_any;
	server.sin6_port = htons(port);
	
	int ret = bind(fd, (struct sockaddr *)&server, sizeof(server));
	if (ret != 0){
		perror("creatSocketTcp_v6 bind failed: ");
		return -1;
	}

	if (listen(fd, 5)<0){
		perror("creatSocketTcp_v6 listen failed: ");
		return -1;
	} 
	return fd;
}

void main(int argc, char** argv)
{
	char buf[1024] = {0};
	int buflen = 0;
	int clientLen = 0;
	
	struct sockaddr client;
	int ret = 0;
	int fd ;
	int fd6;

	if (argc != 2){
		printf("Usage: ./a.out tcp|udp\n");
		return ;
	}else if(strstr(argv[1],"udp")){
		fd = creatSocketUdp(NULL, 8080);
		if(fd < 0){
			printf("%s:%d error\n", __func__, __LINE__);
			return ;
		}
		fd6 = creatSocketUdp_v6(NULL, 8080);
		if(fd < 0){
			printf("%s:%d error\n", __func__, __LINE__);
			return ;
		}
	}else if(strstr(argv[1],"tcp")){
		fd = creatSocketTcp(NULL, 8080);
		if(fd < 0){
			printf("%s:%d error\n", __func__, __LINE__);
			return ;
		}
		fd6 = creatSocketTcp_v6(NULL, 8080);
		if(fd6 < 0){
			printf("%s:%d error\n", __func__, __LINE__);
			return ;
		}
	}else{
		printf("Usage: ./a.out tcp|udp\n");
		return ;
	}
	
	bzero(&client, sizeof(client));
	fd_set readfds;
	int maxFD = 0;
	struct timeval timeVal;
	
	while(1){
		FD_ZERO(&readfds);
		FD_SET(fd, &readfds);
		FD_SET(fd, &readfds);
		
		maxFD = fd6 > fd ? fd6:fd;
		timeVal.tv_sec = 1;
		timeVal.tv_usec = 0;
		
		ret = select(maxFD, &readfds,NULL,NULL,&timeVal);
		if (ret == 0){
			printf("【Timeout!!!】\n");
			continue;
		}else if (ret < 0){
			perror("Whack Fucking error??? :");
			break;
		}else{
			if (FD_ISSET(fd, &readfds)){
				buflen = recvfrom(fd, buf, 1024, 0, (struct sockaddr *)&client, &clientLen);
				if(buflen>0){
					printf("【recv packet v4】: %s\n", buf);
					sendto(fd, buf, buflen, 0, (struct sockaddr *)&client, clientLen);
				}
			}else if(FD_ISSET(fd, &readfds)){
				buflen = recvfrom(fd, buf, 1024, 0, (struct sockaddr *)&client, &clientLen);
				if(buflen>0){
					printf("【recv packet v6】: %s\n", buf);
					sendto(fd, buf, buflen, 0, (struct sockaddr *)&client, clientLen);
				}
			}
		}
	}
	
}
顶一下
(0)
0%
踩一下
(0)
0%
------分隔线----------------------------
你可能感兴趣的内容