多播

版权声明: https://blog.csdn.net/dashoumeixi/article/details/85220221

多播基于udp,让路由器复制数据包传递

基本和udp 程序一样

不同的地方:

对于发送者重要的 ,

1 发送数据不再直接发送到对端,而是发送到多播地址, 但端口还是对端的端口(否则对端套接字无法接受到数据),

   这样通过路由器复制再转发, 对端recvfrom 的ip 将是路由器

2 多播ttl (默认1, 还是修改一下保险一些);

    send_addr.sin_addr.s_addr = inet_addr(ipaddr); //多播地址
	send_addr.sin_port = htons(port);            //对端端口


    DWORD ttl = 64;  //设置多播ttl,默认是1 有可能不太够用
	setsockopt(sock, IPPROTO_IP, IP_MULTICAST_TTL,(char*)&ttl,sizeof(ttl));

对于接受方 :

1 由于是多播,由路由器复制并传递, 所以接受到的ip地址一般来说是路由器.

2 需要bind一下port 用于接受数据,

再来就是socket需要通过 setsockopt 加入多播组,否则无法接受多播组的信息

以上2点代码示意:


    // bind ip,port , 否则无法接受数据
    if (bind(sock, (SOCKADDR*)&local_addr, sizeof(local_addr)) == SOCKET_ERROR){
		print_error(WSAGetLastError());
		return 0;
	}

    //多播结构
	IP_MREQ join_addr;
	join_addr.imr_interface.s_addr = INADDR_ANY;  //加入多播的主机,一般来说就是本机
	join_addr.imr_multiaddr.s_addr = inet_addr(ip); //需要加入的多播地址

    //通过 IP_ADD_MEMBERSHIP 让socket 加入多播
	setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*)&join_addr, sizeof(join_addr));

全部代码:

multi_sender.c

    WSADATA wsadata;
	WSAStartup(MAKEWORD(2, 2), &wsadata);


	SOCKET sock = socket(AF_INET, SOCK_DGRAM, 0);
	char ipaddr[16];
	int port = 0;
	scanf(" %s %d", ipaddr,&port);
	SOCKADDR_IN send_addr;
	printf("ip:%s\n", ipaddr);

	memset(&send_addr, 0, sizeof(send_addr));
	send_addr.sin_addr.s_addr = inet_addr(ipaddr); //发往多播地址
	send_addr.sin_port = htons(port);                      //接受方的端口
	send_addr.sin_family = AF_INET;
	DWORD ttl = 64;
	setsockopt(sock, IPPROTO_IP, IP_MULTICAST_TTL,(char*)&ttl,sizeof(ttl));
	
	char buf[100] = "fuck you";
	for (int i = 0; i < 3; ++i){
		sendto(sock, buf, strlen(buf), 0, (SOCKADDR*)&send_addr, sizeof(send_addr));
		Sleep(1000);
	}
	closesocket(sock);


	WSACleanup();

mutli_recver.c

    char ip[16];
	unsigned short port = 0;
	scanf(" %s %hd", ip, &port);
	WSADATA wsadata;
	WSAStartup(MAKEWORD(2, 2), &wsadata);

	SOCKET sock = socket(AF_INET, SOCK_DGRAM, 0);
	SOCKADDR_IN local_addr;
	memset(&local_addr, 0, sizeof(local_addr));
	local_addr.sin_addr.s_addr = INADDR_ANY;
	local_addr.sin_family = AF_INET;
	local_addr.sin_port = htons(port);    //接受的端口号

	if (bind(sock, (SOCKADDR*)&local_addr, sizeof(local_addr)) == SOCKET_ERROR){
		print_error(WSAGetLastError());
		return 0;
	}

    //加入多播的结构
	IP_MREQ join_addr;
	join_addr.imr_interface.s_addr = INADDR_ANY;   //本机所有接口
	join_addr.imr_multiaddr.s_addr = inet_addr(ip); //加入多播地址

    //通过IP_ADD_MEMBERSHIP 加入多播组
	setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*)&join_addr, sizeof(join_addr));

	char buf[100];
	SOCKADDR_IN client_addr;
	int cli_len = sizeof(client_addr);
	memset(&client_addr, 0, cli_len);
	int n = 0;
	while (1){
		cli_len = sizeof(client_addr);
		n = recvfrom(sock, buf, sizeof(buf), 0, (SOCKADDR*)&client_addr, &cli_len);
		if (n == 0){
			puts("peer closed");
			break;
		}
		else if (n == SOCKET_ERROR){
			print_error(WSAGetLastError());
			break;
		}
		else {
			buf[n] = 0;
			printf("buf:%s, ip from : %s ,port:%d\n", buf,inet_ntoa(client_addr.sin_addr),
				ntohs(client_addr.sin_port));
		}
		
	}



	WSACleanup();

猜你喜欢

转载自blog.csdn.net/dashoumeixi/article/details/85220221
今日推荐