You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

本地主机C语言多播问题:参与者无法接收服务器多播消息

多播消息接收问题排查请求

我将参与者与领导者的代码放在同一个send.c文件中,通过代码结构区分角色。目前领导者可成功发送消息,服务器也已在多播组内广播消息(Wireshark已验证),但参与者无法接收来自服务器的Multicast消息,请求协助排查send.c中参与者端的消息接收问题。


相关代码

主函数代码

int main(int argc, char **argv) {
    ssize_t n;
    int sockfd;
    int recv_s;

    struct user_account currentUser;
    struct sockaddr_in servaddr,localSock;
    struct ip_mreq mreq;
    socklen_t len = sizeof(servaddr);
    
    int roleChoice;
    char sendline[MAX_BUFF], recvline[MAX_BUFF];

    u_int yes=1;

     // user struct instance
    memset(&currentUser, 0, sizeof(currentUser));
    
    sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockfd < 0) {
        perror("Błąd w tworzeniu gniazda");
        exit(EXIT_FAILURE);
    }

    memset(&servaddr, 0, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(PORT);
    if (inet_pton(AF_INET, argv[1], &servaddr.sin_addr) <= 0) {
        perror("Błąd w inet_pton");
        exit(EXIT_FAILURE);
    }

    // mcast socket
    recv_s = socket(AF_INET, SOCK_DGRAM, 0);
    if (recv_s < 0) {
        perror("Błąd w tworzeniu gniazda odbiorczego");
        exit(EXIT_FAILURE);
    }
    setsockopt(recv_s, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes));
    fcntl(recv_s, F_SETFL, O_NONBLOCK);
    #ifdef SO_REUSEPORT
    if (setsockopt(recv_s, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof(yes)) < 0) {
        perror("setsockopt(SO_REUSEPORT) failed");
        exit(EXIT_FAILURE);
    }
    #endif

    // preparing to receive
    memset(&localSock, 0, sizeof(localSock));
    localSock.sin_family = AF_INET;
    localSock.sin_port = htons(MULTICAST_PORT);
    localSock.sin_addr.s_addr = htonl(INADDR_ANY);
    if (bind(recv_s, (struct sockaddr*)&localSock, sizeof(localSock)) < 0) {
        perror("Błąd w bind gniazda odbiorczego multicastu");
        exit(EXIT_FAILURE);
    }
    
    //role 
 if(currentUser.is_instructor){

           //joining the session

           //creating a session
                session_active = 1;
           
          //**
            if (session_active) {
                join_multicast_group(sockfd, MULTICAST_GROUP);
            }

            
            while (session_active) {
                char message[256];
                printf("msg to send (lub 'quit' aby wyjść): ");
                fgets(message, 256, stdin);
                message[strcspn(message, "\n")] = 0;

                if (strncmp(message, "quit", 4) == 0) {
                    break; // Wyjście z pętli
                }

                sprintf(sendline, "MULTICAST_MSG %d: %s", currentUser.training_id, message);
                sendto(sockfd, sendline, strlen(sendline), 0, (const struct sockaddr *)&servaddr, sizeof(servaddr));
                printf("Wysłano wiadomość: %s\n", message);
            }

            
            leave_multicast_group(sockfd, MULTICAST_GROUP);
        }

服务器端代码

else if(strncmp(buffer, "MULTICAST_MSG", 13) == 0) {
                    int session_id;
                    char message_content[MAX_BUFF];
                    if (sscanf(buffer, "MULTICAST_MSG %d: %[^\t\n]", &session_id, message_content) == 2) {
                        send_multicast_message(send_s, message_content, MULTICAST_GROUP, MULTICAST_PORT);
                        printf("Rozesłano wiadomość multicastową do uczestników sesji %d.\n", session_id);
                    } else {
                        printf("Niepoprawny format wiadomości multicastowej.\n");
                    }
void send_multicast_message(int send_socket, const char* message_content, const char* multicast_group, int multicast_port) {
    struct sockaddr_in multicast_addr;
    memset(&multicast_addr, 0, sizeof(multicast_addr));
    multicast_addr.sin_family = AF_INET;
    multicast_addr.sin_addr.s_addr = inet_addr(multicast_group);
    multicast_addr.sin_port = htons(multicast_port);

    if (sendto(send_socket, message_content, strlen(message_content), 0, (struct sockaddr*)&multicast_addr, sizeof(multicast_addr)) < 0) {
        perror("sendto failed");
    } else {
        printf("Rozesłano wiadomość multicastową.\n");
    }
}

send.c中的参与者代码

//joining the session
join_multicast_group(recv_s, MULTICAST_GROUP);
                printf("waiting for mcast messages...\n");
                int session_active = 1;
                while (session_active) {
                    char multicast_message[MAX_BUFF];
                    memset(multicast_message, 0, MAX_BUFF);
                    socklen_t addrlen = sizeof(localSock);
                    ssize_t multicast_len = recvfrom(recv_s, multicast_message, MAX_BUFF, 0, (struct sockaddr *)&localSock, &addrlen);
                    if (multicast_len > 0) {
                        multicast_message[multicast_len] = '\0';
                        printf("mcast msg: %s\n", multicast_message);
                    }

              
                    usleep(100000); // Sleep for 100 milliseconds
                }
                
                leave_multicast_group(recv_s, MULTICAST_GROUP);

额外补充的send_multicast_message代码

void send_multicast_message(int send_socket, const char* message_content, const char* multicast_group, int multicast_port) 
{ struct sockaddr_in multicast_addr; memset(&multicast_addr, 0, sizeof(multicast_addr)); multicast_addr.sin_family = AF_INET; multicast_addr.sin_addr.s_addr = inet_addr(multicast_group); multicast_addr.sin_port = htons(multicast_port); sendto(send_socket, message_content, strlen(message_content), 0, (struct sockaddr*)&multicast_addr, sizeof(multicast_addr)) < 0) }

运行日志

./send (presenter)
enter message('quit' to exit) : hi!

send: hi!

./recv 
received: MULTICAST_MSG 10: hi!

sending multicast.

send mcast message to participants session no 10.

./send (participant)

u joined the session

waiting for mcast messages...

排查建议

  • 检查join_multicast_group实现:确认参与者端调用的join_multicast_group函数是否正确设置了IP_ADD_MEMBERSHIP选项,绑定的socket是否为参与者的recv_s,且多播组地址参数正确。
  • 处理非阻塞socket错误:参与者的recv_s为非阻塞模式,当前代码未处理recvfrom返回的EAGAIN/EWOULDBLOCK以外的错误,可添加判断排查潜在问题:
    if (multicast_len < 0) {
        if (errno != EAGAIN && errno != EWOULDBLOCK) {
            perror("recvfrom failed");
            session_active = 0;
        }
    }
    
  • 确认多播路由与网卡配置:检查参与者主机的多播路由设置,确保多播数据包能到达正确网卡;可在ip_mreq中指定imr_interface为对应网卡IP,强制绑定特定网卡加入多播组。
  • 验证端口与地址一致性:再次确认参与者绑定的MULTICAST_PORT、加入的MULTICAST_GROUP与服务器发送的完全一致,包括宏定义值的正确性。
  • 排查防火墙规则:临时关闭参与者主机的防火墙,测试是否能接收多播消息,确认是否存在端口拦截。

内容的提问来源于stack exchange,提问作者user7777777

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 18:54:54