多播基于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();

dashoumeixi
15 声望1 粉丝

引用和评论

0 条评论