当前位置: 首页 > news >正文

UDP通信

UDP通信

夜把花儿悄悄的开放了,却让百日去领受赞美 ——泰戈尔

详细介绍UDP通信中单播、多播、组播和广播的异同

UDP(User Datagram Protocol)是一种无连接的、简单的传输层协议,常用于快速传输数据,适用于实时性要求高的应用。在UDP通信中,单播、多播、组播和广播是四种不同的数据传输方式,它们各自具有特定的用途和特点。

单播(Unicast):

  • 定义:单播是一种点对点的通信方式,数据从一个发送方传输到一个特定的接收方
  • 特点:单播通信是一对一的通信,数据只发送给一个确定的目标地址。
  • 应用场景:适用于需要将数据准确传输给特定目标的场景,例如网页请求、文件传输等。

多播(Multicast):

  • 定义:多播是一种一对多的通信方式,数据从一个发送方传输到多个确定的接收方
  • 特点:多播通信可以同时发送数据给多个接收方,但这些接收方都必须加入到特定的多播组中。
  • 应用场景:适用于需要将数据同时传输给多个特定接收方的场景,例如视频直播、在线游戏等。

组播(Anycast):

  • 定义:组播是一种一对最近的通信方式,数据从一个发送方传输到一组提供相同服务的接收方中的任意一个
  • 特点:组播通信将数据发送到一组接收方中的最近的一个,通常用于服务寻址,选择最近的接收方处理请求。
  • 应用场景:适用于需要向多个地理位置分布的服务器发送数据,并由最近的服务器处理请求的场景,例如域名系统(DNS)查询。

广播(Broadcast):

  • 定义:广播是一种一对全部的通信方式,数据从一个发送方传输到同一网络中的所有设备
  • 特点:广播通信将数据发送到同一网络中的所有设备,所有设备都能够接收到数据。
  • 应用场景:适用于需要向同一局域网中的所有设备发送数据的场景,例如网络发现、ARP(地址解析协议)请求等。

异同点总结:

  • 共同点:单播、多播、组播和广播都是UDP通信中常用的数据传输方式。
  • 不同点它们之间的主要区别在于目标接收方的数量和确定性,以及数据传输的范围和方式

总结

  • 广播:老师:所有人出去跑操

  • 组播:老师:第一排出去扫地

  • 多播:老师:1号、2号、3号,你们仨给我站起来

  • 单播:老师:4号你来回答下这个问题

总的来说,选择合适的数据传输方式取决于通信需求和网络环境,单播、多播、组播和广播各有其适用的场景和优势。

通过程序区分UDP通信的单播、组播、多播和广播的异同

单播

以下是一个简单的示例程序,用于在Linux上实现UDP单播通信。该程序包括一个服务器和一个客户端,服务器接收来自客户端的消息并将其打印出来。

单播服务器代码(unimsg_server.c):

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>

#define PORT 12345

int main() {
    int sockfd;
    struct sockaddr_in servaddr, cliaddr;
    char buffer[1024];

    // 创建UDP套接字
    if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
        perror("socket creation failed");
        exit(EXIT_FAILURE);
    }

    memset(&servaddr, 0, sizeof(servaddr));
    memset(&cliaddr, 0, sizeof(cliaddr));

    // 绑定服务器地址
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = INADDR_ANY;
    servaddr.sin_port = htons(PORT);

    if (bind(sockfd, (const struct sockaddr *)&servaddr, sizeof(servaddr)) < 0) {
        perror("bind failed");
        close(sockfd);
        exit(EXIT_FAILURE);
    }

    printf("Server is listening on port %d...\n", PORT);

    // 循环接收数据
    while (1) {
        socklen_t len = sizeof(cliaddr);
        int nbytes = recvfrom(sockfd, buffer, sizeof(buffer), 0, (struct sockaddr *)&cliaddr, &len);
        if (nbytes < 0) {
            perror("recvfrom failed");
            close(sockfd);
            exit(EXIT_FAILURE);
        }
        buffer[nbytes] = '\0';
        printf("Received message from client: %s\n", buffer);
    }

    close(sockfd);
    return 0;
}

单播客户端代码(unimsg_client.c):

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>

#define SERVER_IP "127.0.0.1"
#define PORT 12345

int main() {
    int sockfd;
    struct sockaddr_in servaddr;
    char buffer[1024];

    // 创建UDP套接字
    if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
        perror("socket creation failed");
        exit(EXIT_FAILURE);
    }

    memset(&servaddr, 0, sizeof(servaddr));

    // 服务器地址配置
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(PORT);
    if (inet_pton(AF_INET, SERVER_IP, &servaddr.sin_addr) <= 0) {
        perror("Invalid address/ Address not supported");
        close(sockfd);
        exit(EXIT_FAILURE);
    }

    // 从标准输入读取消息并发送到服务器
    printf("Enter message to send to server:\n");
    fgets(buffer, sizeof(buffer), stdin);
    sendto(sockfd, buffer, strlen(buffer), 0, (const struct sockaddr *)&servaddr, sizeof(servaddr));
    printf("Message sent to server\n");

    close(sockfd);
    return 0;
}

使用方法:

  1. 将上述代码分别保存到 unimsg_server.cunimsg_client.c 文件中。
  2. 在终端中编译服务器代码:gcc unimsg_server.c -o unimsg_server
  3. 在另一个终端中编译客户端代码:gcc unimsg_client.c -o unimsg_client
  4. 在第一个终端中运行服务器:./unimsg_server
  5. 在第二个终端中运行客户端:./unimsg_client

您可以在客户端终端中输入消息,然后在服务器终端中看到该消息被接收并打印出来。这就完成了一个简单的UDP单播通信示例。

多播

以下是一个简单的示例程序,用于在Linux上实现UDP多播通信。该程序包括一个多播服务器和一个多播客户端,服务器发送消息到组播地址,客户端接收来自服务器的消息。

多播服务器代码(multicast_server.c):

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>

#define MULTICAST_GROUP "225.0.0.37"
#define PORT 12345

int main() {
    int sockfd;
    struct sockaddr_in servaddr;
    char buffer[1024];
    int nbytes;

    // 创建UDP套接字
    if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
        perror("socket creation failed");
        exit(EXIT_FAILURE);
    }

    memset(&servaddr, 0, sizeof(servaddr));

    // 设置服务器地址
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = inet_addr(MULTICAST_GROUP);
    servaddr.sin_port = htons(PORT);

    // 循环发送数据
    while (1) {
        printf("Enter message to multicast:\n");
        fgets(buffer, sizeof(buffer), stdin);
        nbytes = sendto(sockfd, buffer, strlen(buffer), 0, (const struct sockaddr *)&servaddr, sizeof(servaddr));
        if (nbytes < 0) {
            perror("sendto failed");
            close(sockfd);
            exit(EXIT_FAILURE);
        }
    }

    close(sockfd);
    return 0;
}

多播客户端代码(multicast_client.c):

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>

#define MULTICAST_GROUP "225.0.0.37"
#define PORT 12345

int main() {
    int sockfd;
    struct sockaddr_in servaddr;
    char buffer[1024];

    // 创建UDP套接字
    if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
        perror("socket creation failed");
        exit(EXIT_FAILURE);
    }

    memset(&servaddr, 0, sizeof(servaddr));

    // 设置服务器地址
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = inet_addr(MULTICAST_GROUP);
    servaddr.sin_port = htons(PORT);

    // 加入多播组
    struct ip_mreq mreq;
    mreq.imr_multiaddr.s_addr = inet_addr(MULTICAST_GROUP);
    mreq.imr_interface.s_addr = htonl(INADDR_ANY);
    if (setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) {
        perror("setsockopt");
        close(sockfd);
        exit(EXIT_FAILURE);
    }

    // 循环接收数据
    while (1) {
        int nbytes = recvfrom(sockfd, buffer, sizeof(buffer), 0, NULL, NULL);
        if (nbytes < 0) {
            perror("recvfrom failed");
            close(sockfd);
            exit(EXIT_FAILURE);
        }
        buffer[nbytes] = '\0';
        printf("Received message from server: %s\n", buffer);
    }

    close(sockfd);
    return 0;
}

使用方法:

  1. 将上述代码分别保存到 multicast_server.cmulticast_client.c 文件中。
  2. 在终端中编译服务器代码:gcc multicast_server.c -o multicast_server
  3. 在另一个终端中编译客户端代码:gcc multicast_client.c -o multicast_client
  4. 在第一个终端中运行服务器:./multicast_server
  5. 在第二个终端中运行客户端:./multicast_client

您可以在服务器终端中输入消息,然后在客户端终端中看到该消息被接收并打印出来。这就完成了一个简单的UDP多播通信示例。

组播

以下是一个简单的示例程序,用于在Linux上实现UDP组播通信。该程序包括一个组播服务器和一个组播客户端,服务器发送消息到组播地址,客户端接收来自服务器的消息。

组播服务器代码(groupcast_server.c):

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>

#define GROUPCAST_GROUP "225.0.0.37"
#define PORT 12345

int main() {
    int sockfd;
    struct sockaddr_in servaddr;
    char buffer[1024];
    int nbytes;

    // 创建UDP套接字
    if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
        perror("socket creation failed");
        exit(EXIT_FAILURE);
    }

    memset(&servaddr, 0, sizeof(servaddr));

    // 设置服务器地址
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = inet_addr(GROUPCAST_GROUP);
    servaddr.sin_port = htons(PORT);

    // 循环发送数据
    while (1) {
        printf("Enter message to groupcast:\n");
        fgets(buffer, sizeof(buffer), stdin);
        nbytes = sendto(sockfd, buffer, strlen(buffer), 0, (const struct sockaddr *)&servaddr, sizeof(servaddr));
        if (nbytes < 0) {
            perror("sendto failed");
            close(sockfd);
            exit(EXIT_FAILURE);
        }
    }

    close(sockfd);
    return 0;
}

组播客户端代码(groupcast_client.c):

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>

#define GROUPCAST_GROUP "225.0.0.37"
#define PORT 12345

int main() {
    int sockfd;
    struct sockaddr_in servaddr;
    char buffer[1024];

    // 创建UDP套接字
    if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
        perror("socket creation failed");
        exit(EXIT_FAILURE);
    }

    memset(&servaddr, 0, sizeof(servaddr));

    // 设置服务器地址
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = inet_addr(GROUPCAST_GROUP);
    servaddr.sin_port = htons(PORT);

    // 绑定客户端地址(可选)
    struct sockaddr_in cliaddr;
    memset(&cliaddr, 0, sizeof(cliaddr));
    cliaddr.sin_family = AF_INET;
    cliaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    cliaddr.sin_port = htons(0);
    if (bind(sockfd, (const struct sockaddr *)&cliaddr, sizeof(cliaddr)) < 0) {
        perror("bind failed");
        close(sockfd);
        exit(EXIT_FAILURE);
    }

    // 循环接收数据
    while (1) {
        int nbytes = recvfrom(sockfd, buffer, sizeof(buffer), 0, NULL, NULL);
        if (nbytes < 0) {
            perror("recvfrom failed");
            close(sockfd);
            exit(EXIT_FAILURE);
        }
        buffer[nbytes] = '\0';
        printf("Received message from server: %s\n", buffer);
    }

    close(sockfd);
    return 0;
}

使用方法:

  1. 将上述代码分别保存到 groupcast_server.cgroupcast_client.c 文件中。
  2. 在终端中编译服务器代码:gcc groupcast_server.c -o groupcast_server
  3. 在另一个终端中编译客户端代码:gcc groupcast_client.c -o groupcast_client
  4. 在第一个终端中运行服务器:./groupcast_server
  5. 在第二个终端中运行客户端:./groupcast_client

您可以在服务器终端中输入消息,然后在客户端终端中看到该消息被接收并打印出来。这就完成了一个简单的UDP组播通信示例。

广播

以下是一个简单的示例程序,用于在Linux上实现UDP广播通信。该程序包括一个广播服务器和一个广播客户端,服务器发送消息到广播地址,客户端接收来自服务器的消息。

广播服务器代码(broadcast_server.c):

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>

#define BROADCAST_IP "192.168.0.255"
#define PORT 12345

int main() {
    int sockfd;
    struct sockaddr_in servaddr;
    char buffer[1024];
    int nbytes;

    // 创建UDP套接字
    if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
        perror("socket creation failed");
        exit(EXIT_FAILURE);
    }

    memset(&servaddr, 0, sizeof(servaddr));

    // 设置广播地址
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = inet_addr(BROADCAST_IP);
    servaddr.sin_port = htons(PORT);

    // 设置广播权限
    int broadcast_enable = 1;
    if (setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &broadcast_enable, sizeof(broadcast_enable)) < 0) {
        perror("setsockopt broadcast failed");
        close(sockfd);
        exit(EXIT_FAILURE);
    }

    // 循环发送数据
    while (1) {
        printf("Enter message to broadcast:\n");
        fgets(buffer, sizeof(buffer), stdin);
        nbytes = sendto(sockfd, buffer, strlen(buffer), 0, (const struct sockaddr *)&servaddr, sizeof(servaddr));
        if (nbytes < 0) {
            perror("sendto failed");
            close(sockfd);
            exit(EXIT_FAILURE);
        }
    }

    close(sockfd);
    return 0;
}

广播客户端代码(broadcast_client.c):

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>

#define PORT 12345

int main() {
    int sockfd;
    struct sockaddr_in servaddr, cliaddr;
    char buffer[1024];

    // 创建UDP套接字
    if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
        perror("socket creation failed");
        exit(EXIT_FAILURE);
    }

    memset(&servaddr, 0, sizeof(servaddr));
    memset(&cliaddr, 0, sizeof(cliaddr));

    // 设置服务器地址
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = INADDR_ANY;
    servaddr.sin_port = htons(PORT);

    // 绑定客户端地址
    cliaddr.sin_family = AF_INET;
    cliaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    cliaddr.sin_port = htons(0);
    if (bind(sockfd, (const struct sockaddr *)&cliaddr, sizeof(cliaddr)) < 0) {
        perror("bind failed");
        close(sockfd);
        exit(EXIT_FAILURE);
    }

    // 循环接收数据
    while (1) {
        int nbytes = recvfrom(sockfd, buffer, sizeof(buffer), 0, NULL, NULL);
        if (nbytes < 0) {
            perror("recvfrom failed");
            close(sockfd);
            exit(EXIT_FAILURE);
        }
        buffer[nbytes] = '\0';
        printf("Received message from server: %s\n", buffer);
    }

    close(sockfd);
    return 0;
}

使用方法:

  1. 将上述代码分别保存到 broadcast_server.cbroadcast_client.c 文件中。
  2. 在终端中编译服务器代码:gcc broadcast_server.c -o broadcast_server
  3. 在另一个终端中编译客户端代码:gcc broadcast_client.c -o broadcast_client
  4. 在第一个终端中运行服务器:./broadcast_server
  5. 在第二个终端中运行客户端:./broadcast_client

您可以在服务器终端中输入消息,然后在客户端终端中看到该消息被接收并打印出来。这就完成了一个简单的UDP广播通信示例。

设置组播路由

route add -net 224.0.0.0 netmask 224.0.0.0 eth0 命令在Linux系统中用于添加一条网络路由,这条路由专门处理IPv4组播地址。下面是对命令的详细解释:

命令的作用

该命令的作用是添加一条路由,以便通过指定的网络接口(例如eth0)来处理发送到组播地址范围(224.0.0.0到239.255.255.255)的流量。组播是一种网络通信方法,允许数据从一个源发送到多个特定的接收者。

参数的意义

1. route

route命令用于查看和操作IP路由表。路由表决定了网络流量通过哪条路径发送到目的地。

2. add

add参数指定要添加一条新路由。

3. -net 224.0.0.0

-net参数指定一个网络地址。在这里,224.0.0.0表示组播地址的起始地址。IPv4组播地址范围是从224.0.0.0到239.255.255.255,这些地址专用于多播传输。

4. netmask 224.0.0.0

netmask参数指定了网络掩码。在这里,224.0.0.0的网络掩码用于覆盖组播地址范围。这个掩码表示前三位固定(即二进制1110),适用于组播地址范围:

  • 224.0.0.0在二进制中表示为 1110 0000.0000 0000.0000 0000.0000 0000
  • 掩码224.0.0.0在二进制中表示为 1110 0000.0000 0000.0000 0000.0000 0000

这意味着只要IP地址前3位是111,这条路由规则就适用,这恰好覆盖了组播地址范围。

5. eth0

eth0参数指定了网络接口。这表示所有匹配组播地址的流量都会通过eth0接口传输。eth0通常是系统中第一个以太网接口的名称。

总结

  • route add -net 224.0.0.0:告诉系统要添加一个针对224.0.0.0网络的路由。
  • netmask 224.0.0.0:指定网络掩码,表明该路由适用于所有224.0.0.0239.255.255.255之间的组播地址。
  • eth0:指定了通过eth0网络接口来处理这些组播地址的数据流量。

应用场景

这种配置常用于启用组播应用程序和服务,例如视频流传输、网络会议、在线游戏和其他需要多播通信的应用。通过添加这条路由,系统能够正确处理组播流量,确保数据能够在网络中的多个接收者之间有效传输。

验证路由

可以使用route -nip route命令来查看路由表,确认新添加的路由是否正确应用。

route -n
# 或
ip route show

希望这个详细解释能帮助你理解route add -net 224.0.0.0 netmask 224.0.0.0 eth0命令的作用和每个参数的意义。

相关文章:

  • Elasticsearch 认证模拟题 - 5
  • 结构体相关习题的补充
  • 从0开始学统计-什么是回归?
  • Nuxt.js静态生成与动态路由策略
  • 【论文解读】Performance of AV1 Real-Time Mode
  • 基于java的CRM客户关系管理系统(一)
  • Tomcat
  • 21.Redis之分布式锁
  • mongodb数据库查询调优之explain方法详解
  • 数据结构的希尔排序(c语言版)
  • 【iOS】didReceiveMemoryWarning实例方法
  • 计算机网络基础知识(持续更新中)
  • 【计算机网络】——物理层(图文并茂)
  • 数据结构的快速排序(c语言版)
  • 智能网联汽车翻译
  • 12 FreeRTOS 调试与优化
  • 【Linux网络】端口及UDP协议
  • vscode编辑器创建分支注意事项?!
  • 4月啤酒品类线上销售数据分析
  • Java项目对接redis,客户端是选Redisson、Lettuce还是Jedis?
  • 为发期刊,高校学者偷贩涉密敏感数据!国安部披露间谍案细节
  • 印度外交秘书:印巴军方将于12日再次对话
  • 复旦大学文科杰出教授裘锡圭逝世,享年90岁
  • 习近平同俄罗斯总统普京会谈
  • 第1现场 | 印巴冲突:印50多年来首次举行大规模民防演习
  • 深圳下调公积金利率,209万纯公积金贷款总利息减少9.94万