UDP 组播/多播 C语言实现

目录

逻辑设计:

代码实现

运行结果

224.100.200.1 多播组

224.100.200.52 多播组


思路:

  • PC作为客户机,使用网络调试助手;
  • LS开发板作为服务器端,部署对应程序(代码实现如下);
  • 在UDP基本简单通信的基础上增加两组组播(setsockopt实现,一组也可以),实现组播通信;
  • 运行服务器端程序,打开客户端向组播地址端口发送数据,此时服务器端将收到(多播)的数据发回客户端(单播)完成一次数据收发。
  • 若使用多播进行回复可在代码,recvfrom()后,sendto()之前,修改sockaddrinRemote的IP参数,参考如下代码:
inet_aton(GROUP_ADDR_01, &sockaddrinRemote.sin_addr);

逻辑设计: 

服务器端 程序逻辑设计

代码实现:

#include <stdio.h>
#include <sys/socket.h>

#define __PORT_SERVER 8101                                              /* 服务器端口号                 */
#define GROUP_ADDR_01 "224.100.200.1"                                   /* 组播端口号 1                 */
#define GROUP_ADDR_52 "224.100.200.52"                                  /* 组播端口号 2                 */


int main (int argc, char **argv)
{
    int iRet = -1;                                                      /* 操作结果返回值               */
    int sockFd = -1;                                                    /* socket 描述符                */
    struct sockaddr_in sockaddrinRemote;                                /* 远端地址                     */
    struct sockaddr_in sockaddrinLocal;
    struct ip_mreq mreq;
    socklen_t uiAddrLen = sizeof(struct sockaddr_in);
    char cRecvBuff[257] ={0};
    register ssize_t sstRecv = 0;                                       /* 接收到的数据长度             */

    /*
     * 创建 socket 连接
     */
    sockFd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    if (sockFd < 0) {
        fprintf(stderr, "create socket error.\n");
        return (-1);
    }

    /*
     * 增加地址复用
     */
    iRet = setsockopt(sockFd, SOL_SOCKET, SO_REUSEADDR, &iRet, sizeof(iRet));
    if (iRet < 0) {
        fprintf(stderr, "setsockopt SO_REUSEADDR error.\n");
        return (-1);
    }

    /*
     * 初始化本地地址信息
     */
    memset(&sockaddrinLocal, 0, sizeof(sockaddrinRemote));              /* 清空地址信息                 */
    sockaddrinLocal.sin_len = sizeof(struct sockaddr_in);               /* 地址结构大小                 */
    sockaddrinLocal.sin_family = AF_INET;                               /* 地址族                       */
    sockaddrinLocal.sin_port = htons(__PORT_SERVER);                    /* 绑定服务器端口               */
    sockaddrinLocal.sin_addr.s_addr  = INADDR_ANY;

    /*
     * 绑定本地地址与端口
     */
    iRet = bind(sockFd, (struct sockaddr *)&sockaddrinLocal, sizeof(sockaddrinLocal));
    if (iRet < 0) {                                                     /* 绑定操作失败                 */
        close(sockFd);                                                  /* 关闭已经创建的 socket        */
        fprintf(stderr, "UDP echo server bind error.\n");
        return (-1);                                                    /* 错误返回                     */
    }

    /*
     * 多播结构体初始化
     */
    mreq.imr_multiaddr.s_addr = inet_addr(GROUP_ADDR_01);               /* 多播组的IP地址               */
    mreq.imr_interface.s_addr = htonl(INADDR_ANY);                      /* 加入的客服端主机IP地址       */
    if (setsockopt(sockFd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) == -1)    {
        perror("setsockopt");
        exit(-1);
    }

    mreq.imr_multiaddr.s_addr = inet_addr(GROUP_ADDR_52);               /* 多播组的IP地址               */
    if (setsockopt(sockFd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) == -1)    {
        perror("setsockopt");
        exit(-1);
    }

    while(1)
    {
        memset(cRecvBuff, 0, sizeof(cRecvBuff));
        /*
         * 从远端接收数据
         */
        sstRecv = recvfrom(sockFd, (void *)&cRecvBuff[0], 257, 0, (struct sockaddr *)&sockaddrinRemote,&uiAddrLen);
        if (sstRecv <= 0) {                                             /* 接收数据失败                 */
            if ((errno != ETIMEDOUT ) && (errno != EWOULDBLOCK)) {      /* 非超时与非阻塞               */
                close(sockFd);                                          /* 关闭已经创建的 socket        */
                fprintf(stderr, "UDP echo server recvfrom error.\n");
                return (-1);
            }
            continue;
        }

        sendto(sockFd, (const void *)&cRecvBuff[0], sstRecv, 0, (const struct sockaddr *)&sockaddrinRemote, uiAddrLen);
    }

    /*
     * 多播关闭
     */
    setsockopt(sockFd, IPPROTO_IP, IP_DROP_MEMBERSHIP,&mreq, sizeof(mreq));

    return  (0);
}

运行结果:

224.100.200.1 多播组:

224.100.200.1 多播组

224.100.200.52 多播组:

224.100.200.52 多播组

  • 9
    点赞
  • 108
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
UDP组播通信是一种基于UDP协议的多播通信方式,可以在局域网内实现一对多的数据传输。以下是使用C语言实现UDP组播通信的基本步骤: 1. 创建UDP套接字: 使用`socket()`函数创建一个UDP套接字,指定协议族为`AF_INET`,类型为`SOCK_DGRAM`。 2. 设置组播地址和端口: 使用`setsockopt()`函数设置多播组地址和端口,其中IP地址为组播地址,端口为组播监听的端口。 3. 绑定套接字: 使用`bind()`函数将套接字绑定到本地IP地址和指定的端口上。 4. 加入组播组: 使用`setsockopt()`函数设置套接字的`IP_ADD_MEMBERSHIP`选项,将套接字加入到指定的组播组中。 5. 接收组播数据: 使用`recvfrom()`函数从套接字接收组播数据。 6. 发送组播数据: 使用`sendto()`函数将数据发送到指定的组播地址和端口。 下面是一个简单的UDP组播通信的示例代码: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #define GROUP_ADDR "239.0.0.1" // 组播地址 #define PORT 8888 // 组播端口 int main() { int sockfd; struct sockaddr_in addr; char buffer[1024]; // 创建UDP套接字 sockfd = socket(AF_INET, SOCK_DGRAM, 0); if (sockfd < 0) { perror("socket creation failed"); exit(EXIT_FAILURE); } // 设置组播地址和端口 memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_addr.s_addr = inet_addr(GROUP_ADDR); addr.sin_port = htons(PORT); // 绑定套接字 if (bind(sockfd, (struct sockaddr*)&addr, sizeof(addr)) < 0) { perror("bind failed"); exit(EXIT_FAILURE); } // 加入组播组 struct ip_mreq mreq; memset(&mreq, 0, sizeof(mreq)); mreq.imr_multiaddr.s_addr = inet_addr(GROUP_ADDR); mreq.imr_interface.s_addr = htonl(INADDR_ANY); if (setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) { perror("setsockopt failed"); exit(EXIT_FAILURE); } // 接收组播数据 while (1) { memset(buffer, 0, sizeof(buffer)); if (recvfrom(sockfd, buffer, sizeof(buffer), 0, NULL, NULL) < 0) { perror("recvfrom failed"); exit(EXIT_FAILURE); } printf("Received data: %s\n", buffer); } // 关闭套接字 close(sockfd); return 0; } ``` 这是一个组播接收端的示例代码,可以接收从同一组播地址和端口发送的数据。你可以根据需要修改代码实现组播发送端。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值