C++发送UDP广播

3

我需要一个项目每秒向87.255.255.255和端口4448发送UDP广播,并携带我的项目值。 我已经用C++编写了一些代码,但总是出现错误:

断言“ ::bind(s,(sockaddr *)&si_me,sizeof(sockaddr))!= -1”失败

出错的代码为:

//assert(::bind(s, (sockaddr *)&si_me, sizeof(sockaddr))!=-1);

当我删除这行代码后,程序运行了,但是我在wireshark中没有发现任何东西。

有没有人有解决方案或者一些额外的信息来构建广播发送器?

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <assert.h>
#include <string.h>
#include <ctime>

int main(int argc, char const *argv[]) {

  sockaddr_in si_me, si_other;
  int s;
  printf("Making socket\n");
  assert((s=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP))!=-1);
  fprintf(stderr,"usage %s hostname port\n", argv[0]);
  int port=4448;
  int broadcast=1;
  setsockopt(s, SOL_SOCKET, SO_BROADCAST,
        &broadcast, sizeof broadcast);

        memset(&si_me, 0, sizeof(si_me));
        si_me.sin_family = AF_INET;
        si_me.sin_port = htons(port);
        si_me.sin_addr.s_addr = INADDR_ANY;

  assert(::bind(s, (sockaddr *)&si_me, sizeof(sockaddr))!=-1);

  while(1)
  {
     printf("Send message to broadcast\n");
     char buf[10000];
     strcpy(buf, "test for wireshark");
     unsigned slen=sizeof(sockaddr);
     send(s, buf, sizeof(buf)-1, 0);
     //recvfrom(s, buf, sizeof(buf)-1, 0, (sockaddr *)&si_other, &slen);
     printf("recv: %s\n", buf);
     sleep(1);
  }
}

2
通常在函数中使用assert()是一个不好的主意,因为当调试关闭时,它们将被删除。取而代之的是,调用perror()来查看失败的原因。 - Johnny Cage
我尝试将它更改为perror,但我遇到错误:无法将“bool”转换为参数“1”的“const char *”,以便于“void perror(const char *)”。 - josejos41
1
如果(bind(...)<0) perror("bind()"); 而不是 assert(bind(...)!=-1); - Johnny Cage
我已经做了更改,代码可以运行,但是在Wireshark中没有看到任何传递的内容。 - josejos41
1
如果以前程序中止了,现在你应该能够在控制台中看到错误输出的描述。 - Johnny Cage
首先,端口已经被使用了,我已经更改了端口号。现在我没有收到错误消息,但是在wireshark上我看不到任何东西。 - josejos41
2个回答

4

显然在UNIX下广播存在一些奇怪的问题。因此,这可能会按预期工作,也可能不会。

void errno_abort(const char* header)
{
    perror(header);
    exit(EXIT_FAILURE);
}

int main(int argc, char* argv[])
{
#define SERVERPORT 4567
    struct sockaddr_in send_addr, recv_addr;
    int trueflag = 1, count = 0;
    int fd;
    if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
        errno_abort("socket");
#ifndef RECV_ONLY
    if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST,
                   &trueflag, sizeof trueflag) < 0)
        errno_abort("setsockopt");

    memset(&send_addr, 0, sizeof send_addr);
    send_addr.sin_family = AF_INET;
    send_addr.sin_port = (in_port_t) htons(SERVERPORT);
    // broadcasting address for unix (?)
    inet_aton("127.255.255.255", &send_addr.sin_addr);
    // send_addr.sin_addr.s_addr = htonl(INADDR_BROADCAST);
#endif // ! RECV_ONLY

#ifndef SEND_ONLY
    if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
                   &trueflag, sizeof trueflag) < 0)
        errno_abort("setsockopt");

    memset(&recv_addr, 0, sizeof recv_addr);
    recv_addr.sin_family = AF_INET;
    recv_addr.sin_port = (in_port_t) htons(SERVERPORT);
    recv_addr.sin_addr.s_addr = htonl(INADDR_ANY);

    if (bind(fd, (struct sockaddr*) &recv_addr, sizeof recv_addr) < 0)
        errno_abort("bind");
#endif // ! SEND_ONLY

    while ( 1 ) {
#ifndef RECV_ONLY
        char sbuf[256] = {};
        snprintf(sbuf, sizeof(sbuf), "Hello(%d)!", count++);
        if (sendto(fd, sbuf, strlen(sbuf)+1, 0,
                   (struct sockaddr*) &send_addr, sizeof send_addr) < 0)
            errno_abort("send");
        printf("send: %s\n", sbuf);
        usleep(1000000/2);
#endif // ! RECV_ONLY

#ifndef SEND_ONLY
        char rbuf[256] = {};
        if (recv(fd, rbuf, sizeof(rbuf)-1, 0) < 0)
            errno_abort("recv");
        printf("recv: %s\n", rbuf);
#endif // ! SEND_ONLY
    }
    close(fd);
    return 0;
}

希望这有所帮助。祝你好运。

这对我没有起作用,但将inet_aton("127.255.255.255", &send_addr.sin_addr);更改为 send_addr.sin_addr.s_addr = INADDR_BROADCAST;解决了问题。 - Jonas Due Vesterheden

0
发送大小为10000的UDP数据包可能不是一个好主意。在调用send()时,尝试使用strlen(buffer)代替。这可能是你在shark上看不到任何东西的原因之一。
要找出bind()失败的原因,需要评估errno。
顺便说一句:我记得有一个TCP堆栈实现,即使它应该按照标准工作,也不喜欢将IPPROTO_UDP作为socket()调用的第三个参数。尝试使用0代替。

我已将缓冲区更改为20。这并没有什么作用,但我必须删除assert语句才能编译它。 - josejos41
我把IPPROTO_UDP改成了0,但是在wireshark上没有看到任何传输。 - josejos41

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