【问题标题】:UDP Broadcast packets is seen by tcpdump but not received by linux socketUDP 广播数据包被 tcpdump 看到,但没有被 linux 套接字接收
【发布时间】:2021-07-03 08:04:45
【问题描述】:

下图为 ifconfig 命令输出

root@ABC20202407:~# ifconfig eth0      Link encap:Ethernet  HWaddr 4E:AA:37:6F:40:BE
          inet addr:192.168.0.24  Bcast:10.177.245.255  Mask:255.255.254.0
          inet6 addr: fe80::4caa:37ff:fe6f:40be/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:12451 errors:0 dropped:0 overruns:0 frame:0
          TX packets:17071 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:2359838 (2.2 MiB)  TX bytes:2537204 (2.4 MiB)

eth1      Link encap:Ethernet  HWaddr AA:BB:CC:DD:11:AA
          inet addr:192.168.253.10  Bcast:192.168.253.255  Mask:255.255.255.0
          inet6 addr: fe80::a8bb:ccff:fedd:11aa/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:1624 errors:0 dropped:0 overruns:0 frame:0
          TX packets:23 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:211802 (206.8 KiB)  TX bytes:1858 (1.8 KiB)

lo        Link encap:Local Loopback
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:172 errors:0 dropped:0 overruns:0 frame:0
          TX packets:172 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1
          RX bytes:15824 (15.4 KiB)  TX bytes:15824 (15.4 KiB)

设备连接到“eth1”以太网接口,该接口周期性地广播 UDP 数据包 10 秒。 我正在使用以下代码,

#include <iostream>
#include <sys/socket.h> 
#include <arpa/inet.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/uio.h>
#include <fcntl.h>
#include <termios.h>
#include <sys/ioctl.h>
#include <string>

#define MAXRECVSTRING 134

int rwho_sock,src_addr_len, nBytes;
unsigned int rwhoSendStringLen; 
int broadcastPermission = 1;
char recvString[MAXRECVSTRING+1];

struct sockaddr_in rwhoBroadcastAddr;    /* Broadcast address */
struct sockaddr_in rwhoSrcBroadcastAddr; /* Source address */

int recvStringLen;

void rwho_receive() {
    /* Create socket for sending/receiving datagrams */
    if ((rwho_sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
        std::cout << "1.Error !!! socket() failed \n";
    else
        std::cout << "rwho_sock socket() created \n";

    std::string devname = "eth1";

    if (setsockopt(rwho_sock, SOL_SOCKET, SO_BINDTODEVICE, devname.c_str(), devname.size()) < 0) {
        std::cout << "1.Error !!! setsockopt() failed \n";

    } else {
        std::cout << "rwho_sock socket() set successfully \n";
    }

    std::cout << __LINE__ << std::endl; 

    memset(&rwhoSrcBroadcastAddr, 0, sizeof(rwhoSrcBroadcastAddr));
    rwhoSrcBroadcastAddr.sin_family = AF_INET;
    rwhoSrcBroadcastAddr.sin_addr.s_addr = htonl(INADDR_ANY); 
    rwhoSrcBroadcastAddr.sin_port = htons(7000);


    memset(&rwhoBroadcastAddr, 0, sizeof(rwhoBroadcastAddr));
    rwhoBroadcastAddr.sin_family = AF_INET;
    rwhoBroadcastAddr.sin_addr.s_addr = inet_addr("192.168.253.10");
    rwhoBroadcastAddr.sin_port = htons(7000);

    src_addr_len = sizeof(rwhoBroadcastAddr);

    std::cout << "src_addr_len = " << src_addr_len << std::endl;
    std::cout << "rwho_sock = " << rwho_sock << std::endl; 

    if (bind(rwho_sock, (struct sockaddr *) &rwhoBroadcastAddr, sizeof(rwhoBroadcastAddr)) < 0){
        std::cout << "rwho Bind Error !!! " << std::endl;
    } else{
        std::cout << "rwho Bind successful " << std::endl;
    }

    nBytes = recvfrom(rwho_sock, recvString, MAXRECVSTRING, MSG_WAITALL, (struct sockaddr*)&rwhoSrcBroadcastAddr, reinterpret_cast<socklen_t*>(&src_addr_len));

    std::cout << "nBytes = %d \n" << nBytes << std::endl;
    std::cout << "Received: %s \n" << recvString << std::endl;  

}

int main() {
    int r = 0;
    while(true) {
        rwho_receive();
    }
}

上面代码的输出是

root@ABC20202407:~# ./so.out
rwho_sock socket() created
rwho_sock socket() set successfully
41
src_addr_len = 16
rwho_sock = 3
rwho Bind successful

并且代码在接收呼叫时被阻止, 但是我们可以在 tcpdump 上看到接收到的数据包

root@ABC20202407:~#  tcpdump -i eth1 -vv -A
tcpdump: listening on eth1, link-type EN10MB (Ethernet), capture size 262144 bytes
21:00:18.704211 IP (tos 0x0, ttl 64, id 54638, offset 0, flags [DF], proto UDP (17), length 116)
    192.168.253.1.7000 > 192.168.253.255.7000: [udp sum ok]  rx type 0 cid c0a8fd01 call# 1617793781 seq 1129534588 ser 1431196672 (88)
E..t.n@.@............X.X.`J.........`m..CST|UNT................................ ....................................

任何帮助都非常感谢,在此先感谢。

我已经解决了大多数 stackoverflow 和 stackexchange 问题,但没有一个能解决我的问题。

【问题讨论】:

  • 自从我上次做这样的事情已经有好几年了。但据我记得,如果你将数据包发送到 eth1,如果配置了路由,你只能在 localhost 上看到它。但不确定这是否是这里的问题。也不确定操作系统(unix,windows,..)之间的行为是否有所不同

标签: c++ c linux sockets networking


【解决方案1】:

为了接收广播包,需要设置SO_BROADCASTsocket选项。

int bcast = 1;
int rval = setsockopt(rwho_sock, SOL_SOCKET, SO_BROADCAST, &bcast, sizeof(bcast));

【讨论】:

    【解决方案2】:

    在 Linux 上,您需要绑定到接口的广播地址(例如 192.168.253.255)或INADDR_BROADCAST,才能接收广播。

       rwhoBroadcastAddr.sin_addr.s_addr = INADDR_BROADCAST;
    

    为避免“使用中的地址”错误,设置套接字选项SO_REUSEADDR

       int on = 1;
       if (setsockopt(rwho_sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) {
           perror("SO_REUSEADDR");
       }
    

    注意:在 Linux 上,SO_BROADCAST 仅用于发送广播,接收广播不需要它(不知道其他操作系统)。

    最后:rwhoSrcBroadcastAddr不用填,recvfrom填(是输出参数)。

    【讨论】:

    • 感谢您的帮助,但它似乎不起作用,它被接收呼叫阻止。你觉得有什么路由问题吗?
    • 还有一个防火墙问题。我们在刷新 iptable 后进行了测试,我们收到了数据包。感谢您的支持。
    猜你喜欢
    • 2023-03-23
    • 1970-01-01
    • 1970-01-01
    • 2011-03-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多