在Linux中如何使用C进行UDP广播?

37

如何在Linux中使用C语言进行UDP广播?


编程方式,还是通过工具/软件? - ayaz
4个回答

52

在很多IP堆栈中,比如Linux,这段代码会不起作用。你的套接字必须具有广播权限。尝试这样做:

bcast_sock = socket(AF_INET, SOCK_DGRAM, 0);
int broadcastEnable=1;
int ret=setsockopt(bcast_sock, SOL_SOCKET, SO_BROADCAST, &broadcastEnable, sizeof(broadcastEnable));

/* Add other code, sockaddr, sendto() etc. */

8
没错!如果您不给套接字广播权限,您将收到“权限被拒绝”的错误消息。 - Chang Hyun Park
7
这种行为实际上是 POSIX 所要求的,详见 http://pubs.opengroup.org/onlinepubs/009695399/functions/sendto.html。如果套接字没有设置 SO_BROADCAST 选项,sendto() 将会失败。 - Jan Smrčina
4
请问“this code does not work”是什么意思?问题中并没有包含任何代码。 (翻译说明:根据要求进行翻译,尽可能保持原文意思的前提下,使句子通俗易懂。) - Emil S.
@EmilS。看看其他答案。它们都是从'08年的,而这个是从'12年的。我已经有了没有setsockopt的代码,但它不起作用。所以这就是为什么。我投赞成票。 - Mikolasan
3
这个回答中的代码样本确实回答了问题并且使用了最新的代码,但我仍然不知道this code does not work指的是哪段代码。如果是指其他回答中的代码,则应该是“The code from the other answers does not work”。如果是指特定的回答,您可以使用“来自[user]的回答中的代码无法正常工作”或甚至是“无法单独工作”。这里的措辞只是让这个回答有点难以理解。 - Emil S.

16

Unwind说得没错,但应该使用'sendto'。

以下是一个示例,假设您已经有了一个套接字。这个示例取自clamav

static void
broadcast(const char *mess)
{
    #define BROADCAST_PORT 30000u
    struct sockaddr_in s;

    int broadcastSock = socket(AF_INET, SOCK_DGRAM, 0);
    
    if(broadcastSock < 0)
        return;

    memset(&s, '\0', sizeof(struct sockaddr_in));
    s.sin_family = AF_INET;
    s.sin_port = htons(BROADCAST_PORT)
    s.sin_addr.s_addr = INADDR_BROADCAST; /* This is not correct : htonl(INADDR_BROADCAST); */

    cli_dbgmsg("broadcast %s to %d\n", mess, broadcastSock);
    if(sendto(broadcastSock, mess, strlen(mess), 0, (struct sockaddr *)&s, sizeof(struct sockaddr_in)) < 0)
        perror("sendto");
}

请将源链接更正为有效的HTML锚点元素。 - sgnsajgon

4

通常使用Berkeley sockets API,向已知broadcast-class IP地址发送一个或多个数据报。


我修改了建议的函数,以匹配Shodane挖掘出来的实际代码。 - unwind

3

最近我写了一个UDP多播服务器进行测试。要订阅多播,您需要将客户端订阅到多播组225.0.0.37端口12346和端口12345(两个源 - 一个源发送“Hello, World!”另一个源发送“Bye, Office!”)。

我一直在使用它来测试我的客户端,客户端和服务器都在同一台计算机上运行,因此可能会有一些问题,但首先请尝试。

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

#include <unistd.h>


#define BYE_OFFICE 12346
#define HELLO_PORT 12345
#define HELLO_GROUP "225.0.0.37"

int main(int argc, char *argv[])
{
    struct sockaddr_in addr;
    struct sockaddr_in addr2;
    int fd;
    int fd2;
    char *message = "Hello, World!";
    char *message2 = "Bye, Office!";

    if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
    {
        perror("socket");
        exit(1);
    }

    if ((fd2 = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
    {
        perror("socket");
        exit(1);
    }

    /* set up destination address */
    memset(&addr,0,sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = inet_addr(HELLO_GROUP);
    addr.sin_port=htons(HELLO_PORT);

    memset(&addr2,0,sizeof(addr2));
    addr2.sin_family = AF_INET;
    addr2.sin_addr.s_addr = inet_addr(HELLO_GROUP);
    addr2.sin_port=htons(BYE_OFFICE);

    while (1)
    {
        if (sendto(fd, message, strlen(message), 0,(struct sockaddr *) &addr, sizeof(addr)) < 0)
        {
            perror("sendto");
            exit(1);
        }
        sleep(3);
        if (sendto(fd2, message2, strlen(message2), 0,(struct sockaddr *) &addr2, sizeof(addr2)) < 0)
        {
            perror("sendto2");
            exit(1);
        }
        sleep(3);
    }
}

10
这与问题有什么关系?问题是关于广播,而这是关于多播。 - xaxxon
1
不想唤醒一个已经死掉的线程,但我认为这与问题有关,只是可能多了一点冗长。在我看来,这是本页上更有用的答案,除了提到您的套接字需要广播权限之外。虽然多播和广播是不同的,但这段代码在功能上与广播相同。 - Will Eccles
这不是组播,你仍在执行单播。 - tripulse

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接