我重写了一些示例代码,这些代码是我在Internet上找到的,用于在Centos6.9上接收多播数据报,并且可以在一台机器上正常工作
但是当我从另一台计算机上运行它时,它会超时。 (这可能并不重要,但是已经超过了Centos7.5) 最终,我意识到这是防火墙(运行此命令以卸载防火墙)
systemctl stop firewalld
这是我得到的良好输出:
[root@aio-163-124 ~]# ./listener -i 239.0.32.12 -p 11115 -n eth1
allocating udp socket on IPv4 family
address is: 10.70.150.154
binding to:
multi cast ip: 0.0.0.0 (0)
multi cast port: 11115 (27435)
joining multicast on:
multi cast addr: 239.0.32.12 (203423983)
network interface: 10.70.150.154 (2593539594)
setting read timeout of 30 seconds and 0 microseconds
Read: 1316bytes
Read: 1316bytes
Read: 1316bytes
Read: 1316bytes
Read: 1316bytes
Read: 1316bytes
Read: 1316bytes
Read: 1316bytes
Read: 1316bytes
Read: 1316bytes
leaving multicast
closing
我附上完整的代码
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <fcntl.h>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cstdint>
#include <iostream>
#include <iomanip>
#include <string>
#include <stdexcept>
const std::string MCAST_GROUP = "239.0.32.12";
const int MCAST_PORT = 11115;
const std::string DST_IFACE_NAME = "enp6s0";
const std::string DST_IFACE_IP = "10.65.150.155";
uint32_t convert_string_ipv4_address_to_uint32_t(const std::string &address)
{
unsigned char buf[sizeof(struct in6_addr)];
bzero(buf, sizeof(buf));
int s = inet_pton(AF_INET, address.c_str(), buf);
if (s <= 0)
{
if (s == 0) std::cerr << "Not in presentation format" << std::endl;
else
{
throw std::runtime_error("inet_pton");
}
}
return *reinterpret_cast<uint32_t *>(buf);
}
class SocketResource
{
int sd_;
std::string mcast_group_;
int mcast_port_;
std::string dst_iface_name_;
std::string dst_iface_ip_;
void convert_iface_name_to_ip_()
{
struct ifreq ifr;
ifr.ifr_addr.sa_family = AF_INET;
strcpy(ifr.ifr_name, this->dst_iface_name_.c_str());
if (ioctl(this->sd_, SIOCGIFADDR, &ifr) < 0)
{
throw std::runtime_error("Unable to find address");
}
this->dst_iface_ip_ = inet_ntoa((reinterpret_cast<struct sockaddr_in *>(&ifr.ifr_addr))->sin_addr);
/* display result */
std::cout << "address is: " << this->dst_iface_ip_ << std::endl;
}
public:
SocketResource(const std::string &mcast_group, int mcast_port, const std::string &dst_iface_name) :
mcast_group_(mcast_group)
, mcast_port_(mcast_port)
, dst_iface_name_(dst_iface_name)
{
/*
* Create a datagram socket on which to receive.
*/
std::cout << "allocating udp socket on IPv4 family" << std::endl;
this->sd_ = socket(AF_INET, SOCK_DGRAM, 0);
if (this->sd_ < 0)
{
throw std::runtime_error("opening datagram socket");
}
this->convert_iface_name_to_ip_();
}
~SocketResource()
{
std::cout << "closing" << std::endl;
close(this->sd_);
}
int set_sock_option(int level, int optname, void *optval, socklen_t optlen)
{
return setsockopt(this->sd_, level, optname, optval, optlen);
}
void set_sock_opt_reuse()
{
/*
* Enable SO_REUSEADDR to allow multiple instances of this
* application to receive copies of the multicast datagrams.
*/
int reuse = 1;
if (this->set_sock_option(SOL_SOCKET, SO_REUSEADDR,
reinterpret_cast<void *>(&reuse), sizeof(reuse)) < 0)
{
throw std::runtime_error("setting SO_REUSEADDR");
}
}
void bind_to_socket()
{
/*
* Bind to the proper port number with the IP address
* specified as INADDR_ANY.
*/
struct sockaddr_in localSock;
bzero(reinterpret_cast<void *>(&localSock), sizeof(localSock));
localSock.sin_family = AF_INET;
localSock.sin_port = htons(this->mcast_port_);
localSock.sin_addr.s_addr = INADDR_ANY;
char str[INET_ADDRSTRLEN];
inet_ntop(localSock.sin_family, reinterpret_cast<char *>(&localSock.sin_addr.s_addr), str, INET_ADDRSTRLEN);
std::cout
<< "binding to:" << std::endl
<< "\tmulti cast ip: " << str << " (" << localSock.sin_addr.s_addr << ")" << std::endl
<< "\tmulti cast port: " << this->mcast_port_ << " (" << localSock.sin_port << ")" << std::endl;
if (bind(this->sd_, reinterpret_cast<struct sockaddr *>(&localSock), sizeof(localSock)))
{
throw std::runtime_error("binding to address");
}
}
void join_mcast()
{
/*
* Join the multicast group 239.0.32.12 on the local 10.65.150.155
* interface. Note that this IP_ADD_MEMBERSHIP option must be
* called for each local interface over which the multicast
* datagrams are to be received.
*/
struct ip_mreq group;
group.imr_multiaddr.s_addr = convert_string_ipv4_address_to_uint32_t(this->mcast_group_);
group.imr_interface.s_addr = convert_string_ipv4_address_to_uint32_t(this->dst_iface_ip_);
std::cout
<< "joining multicast on:" << std::endl
<< "\tmulti cast addr: " << this->mcast_group_ << " (" << group.imr_multiaddr.s_addr << ")" << std::endl
<< "\tnetwork interface: " << this->dst_iface_ip_ << " (" << group.imr_interface.s_addr << ")" << std::endl;
if (this->set_sock_option(IPPROTO_IP, IP_ADD_MEMBERSHIP,
reinterpret_cast<void *>(&group), sizeof(group)) < 0)
{
throw std::runtime_error("adding multicast group");
}
}
void leave_mcast()
{
/*
* Join the multicast group 239.0.32.12 on the local 10.65.150.155
* interface. Note that this IP_ADD_MEMBERSHIP option must be
* called for each local interface over which the multicast
* datagrams are to be received.
*/
std::cout << "leaving multicast" << std::endl;
struct ip_mreq group;
group.imr_multiaddr.s_addr = convert_string_ipv4_address_to_uint32_t(this->mcast_group_);
group.imr_interface.s_addr = convert_string_ipv4_address_to_uint32_t(this->dst_iface_ip_);
if (this->set_sock_option(IPPROTO_IP, IP_DROP_MEMBERSHIP,
reinterpret_cast<void *>(&group), sizeof(group)) < 0)
{
throw std::runtime_error("dropping multicast group");
}
}
bool read_timeout()
{
fd_set set;
FD_ZERO(&set); /* clear the set */
FD_SET(this->sd_, &set); /* add our file descriptor to the set */
struct timeval timeout;
timeout.tv_sec = 30;
timeout.tv_usec = 0;
std::cout << "setting read timeout of " << timeout.tv_sec << " seconds and " << timeout.tv_usec << " microseconds" << std::endl;
int rv = select(this->sd_ + 1, &set, NULL, NULL, &timeout);
if (rv == -1) throw std::runtime_error("select"); /* an error accured */
else if (rv == 0) std::cerr << "timeout" << std::endl; /* a timeout occured */
return rv == -1 || rv == 0;
}
void read_from_socket()
{
/*
* Read from the socket.
*/
const size_t MSGBUFSIZE = 0x4000;
char databuf[MSGBUFSIZE];
int size = read(this->sd_, databuf, sizeof(databuf));
if (size < 0)
{
throw std::runtime_error("reading datagram message");
}
std::cout << "Read: " << size << "bytes" << std::endl;
}
};
void print_usage_and_die(const std::string &name)
{
std::cout <<
"Usage: " << name << " <options> :" << std::endl
<< "\t[-h] This help message." << std::endl
<< "\t[-i multicast ip] multicast ip." << std::endl
<< "\t[-p port] multicast port." << std::endl
<< "\t[-n interface] ethernet interface." << std::endl
<< "Example: " << name << " -i " << MCAST_GROUP << " -p " << MCAST_PORT << " -n " << DST_IFACE_NAME << std::endl
;
exit(EXIT_FAILURE);
}
void get_options(int argc, char *argv[], std::string &mcast_group, int &mcast_port, std::string &dst_iface_name)
{
char c = 0;
while ((c = getopt(argc, argv, "hi:p:s:n:")) != EOF)
{
switch (c)
{
case 'i':
mcast_group = optarg;
break;
case 'p':
mcast_port = std::stol(optarg);
break;
case 'n':
dst_iface_name = optarg;
break;
case 'h':
case '?':
print_usage_and_die(argv[0]);
default:
abort();
}
}
}
int main(int argc, char *argv[])
{
/* -------------------------------------------------------------
*
* Receive Multicast Datagram code example.
*
* -------------------------------------------------------------
*/
std::string mcast_group = MCAST_GROUP;
int mcast_port = MCAST_PORT;
std::string dst_iface_name = DST_IFACE_NAME;
get_options(argc, argv, mcast_group, mcast_port, dst_iface_name);
try
{
SocketResource socket_resource(mcast_group, mcast_port, dst_iface_name);
socket_resource.set_sock_opt_reuse();
socket_resource.bind_to_socket();
socket_resource.join_mcast();
if (socket_resource.read_timeout()) return EXIT_FAILURE; /* an error accured */
for (int i = 0; i < 10; ++i)
{
socket_resource.read_from_socket();
}
socket_resource.leave_mcast();
} catch (const std::runtime_error &err)
{
perror(err.what());
} catch (...)
{
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
这是如何编译它:
g++ -std=c++11 -g -o listener listener.cpp
tcpdump命令行:
tcpdump -n -ieth1 "host 10.70.161.248 and host 10.70.162.131"
输出:
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth1, link-type EN10MB (Ethernet), capture size 262144 bytes
11:26:46.871261 IP 10.70.162.131.55025 > 10.70.161.248.42761: UDP, length 1316
11:26:51.888180 ARP, Request who-has 10.70.161.248 tell 10.70.162.131, length 46
11:26:51.888194 ARP, Reply 10.70.161.248 is-at fa:16:3e:47:19:4f, length 28
11:54:14.390021 IP 10.70.162.131.55025 > 10.70.161.248.11115: UDP, length 1316
11:54:14.392582 IP 10.70.162.131.55025 > 10.70.161.248.11115: UDP, length 1316
11:54:14.395470 IP 10.70.162.131.55025 > 10.70.161.248.11115: UDP, length 1316
11:54:14.397505 IP 10.70.162.131.55025 > 10.70.161.248.11115: UDP, length 1316
11:54:14.400377 IP 10.70.162.131.55025 > 10.70.161.248.11115: UDP, length 1316
11:54:14.403287 IP 10.70.162.131.55025 > 10.70.161.248.11115: UDP, length 1316
11:54:14.406285 IP 10.70.162.131.55025 > 10.70.161.248.11115: UDP, length 1316
11:54:14.408535 IP 10.70.162.131.55025 > 10.70.161.248.11115: UDP, length 1316
11:54:14.412468 IP 10.70.162.131.55025 > 10.70.161.248.11115: UDP, length 1316
11:54:14.415034 IP 10.70.162.131.55025 > 10.70.161.248.11115: UDP, length 1316
11:54:14.417615 IP 10.70.162.131.55025 > 10.70.161.248.11115: UDP, length 1316
11:54:14.417633 IP 10.70.161.248 > 10.70.162.131: ICMP 10.70.161.248 udp port 11115 unreachable, length 556
11:54:19.393190 ARP, Request who-has 10.70.161.248 tell 10.70.162.131, length 46
11:54:19.393213 ARP, Reply 10.70.161.248 is-at fa:16:3e:47:19:4f, length 28