【问题标题】:UDP broadcasting on same machine?UDP广播在同一台机器上?
【发布时间】:2014-02-12 00:29:40
【问题描述】:

我写了一个broadcaster和一个listener,它们recvfrom系统上的一个特定端口。我为 listener 中的套接字使用了 REUSEADDR 选项,以使 listener 的多个实例监视同一系统上的同一端口。

当我在不同的机器上运行 listener 并从另一台机器发送数据包时,所有的 listeners 都会收到数据包。但是当我在同一台机器上运行多个 listener 实例时,如果我尝试发送 udp 数据包,则只有 listener 的第一个实例会获取数据包而不是全部。我想在同一台机器上广播 UDP 数据包,并希望所有的侦听器都能接收到数据包。我在linux上。

我遵循了 Beej 的指南。

编辑 01

监听代码

/*
** listener.c -- a datagram sockets "server" demo
*/

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>

#define MYPORT "4950"   // the port users will be connecting to

#define MAXBUFLEN 100

// get sockaddr, IPv4 or IPv6:
void *get_in_addr(struct sockaddr *sa)
{
        if (sa->sa_family == AF_INET) {
                return &(((struct sockaddr_in*)sa)->sin_addr);
        }

        return &(((struct sockaddr_in6*)sa)->sin6_addr);
}

int main(int argc, char *argv[])
{
        int sockfd;
        struct addrinfo hints, *servinfo, *p;
        int rv;
        int numbytes;
        struct sockaddr_storage their_addr;
        char buf[MAXBUFLEN];
        socklen_t addr_len;
        char s[INET6_ADDRSTRLEN];

        int reuse_addr = 1;


        memset(&hints, 0, sizeof hints);
        hints.ai_family = AF_UNSPEC; // set to AF_INET to force IPv4
        hints.ai_socktype = SOCK_DGRAM;
        hints.ai_flags = AI_PASSIVE; // use my IP

        if ((rv = getaddrinfo(NULL, MYPORT, &hints, &servinfo)) != 0) {
                fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
                return 1;
        }

        // loop through all the results and bind to the first we can
        for(p = servinfo; p != NULL; p = p->ai_next) {
                if ((sockfd = socket(p->ai_family, p->ai_socktype,
                                p->ai_protocol)) == -1) {
                        perror("listener: socket");
                        continue;
                }

                if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) {

                        if(errno == EADDRINUSE)
                        {
                                if(setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR,
                                                &reuse_addr, sizeof reuse_addr) < 0)
                                        perror("setsockopt(): REUSEADDR\n"),exit(1);
                        }
                        else
                        {
                                close(sockfd);
                                perror("listener: bind");
                                continue;
                        }
                }
                break;
        }

        if (p == NULL) {
                fprintf(stderr, "listener: failed to bind socket\n");
                return 2;
        }

        freeaddrinfo(servinfo);

        printf("listener: waiting to recvfrom...\n");

        addr_len = sizeof their_addr;
        if ((numbytes = recvfrom(sockfd, buf, MAXBUFLEN-1 , 0,
                (struct sockaddr *)&their_addr, &addr_len)) == -1) {
                perror("recvfrom");
                exit(1);
        }

        printf("listener: got packet from %s\n",
                inet_ntop(their_addr.ss_family,
                        get_in_addr((struct sockaddr *)&their_addr),
                        s, sizeof s));
        printf("listener: packet is %d bytes long\n", numbytes);
        buf[numbytes] = '\0';
        printf("listener: packet contains \"%s\"\n", buf);

        close(sockfd);

        return 0;
}

【问题讨论】:

  • 您的发件人发送到哪个 IP 地址?如果它正在发送到 127.0.0.1,那么它正在发送单播数据包,并且只有一个侦听器会接收它们。如果它发送到您本地网络的广播地址(例如,如果您在 192.168.0.x 网络上,则为 192.168.0.255,或者如果您在 10.0.xy 网络上,则为 10.255.255.255,依此类推)然后所有侦听器应该会收到数据包。
  • 我尝试发送到 255.255.255.255、localhost 和 0.0.0.0。在所有情况下,只有一个侦听器获取数据包。
  • 试试你局域网的广播地址(基本上是你的 IP 地址按位或按位而不是你的网络掩码;例如对于 ip=192.168.2.5 netmask=255.255.255.0,broadcast_address=( 192.168.2.5 | 0.0.0.255) = 192.168.2.255
  • 我现在也试过了。它没有用。我也尝试设置 SO_REUSEPORT 选项。但它似乎在 linux 中不可用; gcc 抛出编译错误
  • 你能发布listner代码吗?

标签: linux sockets udp broadcast


【解决方案1】:

在 SYSFS 中使用 echo 将 accept_local 设为 1

/proc/sys/net/ipv4/conf/all # cat accept_local
1

这将允许本地通信。

【讨论】:

    【解决方案2】:

    在 linsener 中将套接字选项设置为 SO_REUSEPORT

    SO_REUSEPORT - 套接字选项允许同一主机上的多个套接字绑定到同一端口

    【讨论】:

    • SO_REUSEPORT 在 linux 中不可用,我想。当我编译时,它 gcc 说 SO_REUSEPORT 未声明。
    • 操作系统和内核版本是多少?
    • 这是 uname >>> Linux tsus007 2.6.18-128.el5 #1 SMP Wed Dec 17 11:41:38 EST 2008 x86_64 x86_64 x86_64 GNU 的输出/Linux
    • 有没有其他方法可以在同一台机器上播放??强制通过 UDP
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-12-24
    • 1970-01-01
    • 2012-10-29
    • 1970-01-01
    • 2017-12-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多