C++发送UDP广播

c++ send UDP broadcast

对于一个项目,我需要每秒向 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);
  }
}

发送大小为 10000 的 UDP 数据包可能不是一个好主意。 尝试在调用 send() 时使用 strlen(buffer)。这可能是您在 shark 上看不到任何东西的原因。

要找到 bind() 失败的原因,您需要评估 errno。

顺便说一句:我记得一个 TCP 堆栈实现,它不喜欢 IPPROTO_UDP 作为 socket() 调用的第三个参数,即使它应该根据标准工作。尝试改用 0。

显然在 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;
}

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