c++ - 在 ipv6 链接范围单播 udp 客户端-服务器守护进程中应用 boost::asio::ip::udp,有时有效,但有时无效

标签 c++ boost boost-asio ipv6

我在使用 boost::asio::ip::udp 实现一个简单的 udp 客户端-服务器时遇到了一个问题。如果我将服务器绑定(bind)到一个 ipv6 链接范围的单播地址,它在一些 PC 上可以工作,但不能在其他一些 PC 上。

//main.cpp
#include <iostream>
#include <string>
#include <vector>
#include <cstring>

#include <boost/asio.hpp>
#include <boost/format.hpp>

void test_udp_server(std::string const& host_, std::string const& port_)
{
    boost::asio::io_service io_service;
    boost::asio::ip::udp::socket socket(io_service);
    boost::asio::ip::udp::resolver resolver(io_service);
    boost::asio::ip::udp::endpoint endpoint= *resolver.resolve(boost::asio::ip::udp::resolver::query(host_, port_));
    socket.open(endpoint.protocol());

    std::cout << "address:" << endpoint.address().to_string() << " port:" << port_ << std::endl; 

    boost::system::error_code e;
    socket.bind(endpoint, e);
    if (e)
    {
        std::cerr << "bind error:" << e.message() << std::endl;
        return;
    }

    //recieve from
    boost::asio::ip::udp::endpoint remote_endpoint;
    char buffer[4096];
    unsigned int size;

    while (1)
    {
        memset(buffer, 0, 4096);
        size = 0;
        size = socket.receive_from(boost::asio::buffer(buffer, 4096), remote_endpoint);

        std::cout << "receive: " << std::string(buffer) << std::endl;
    }
}

void test_udp_client(std::string const& host_, std::string const& port_)
{
    boost::asio::io_service io_service;
    boost::asio::ip::udp::socket socket(io_service);
    boost::asio::ip::udp::resolver resolver(io_service);
    boost::asio::ip::udp::endpoint dest_endpoint= *resolver.resolve(boost::asio::ip::udp::resolver::query(host_, port_));
    socket.open(dest_endpoint.protocol());

    int i = 0;
    boost::system::error_code e;

    while (i < 10)
    {
        std::string msg = boost::str(boost::format("udp message %d") % i);

        socket.send_to(boost::asio::buffer(msg.c_str(), msg.size()), dest_endpoint, boost::asio::detail::message_do_not_route, e);
        if (!e)
        {
            std::cout << "send: " << msg << std::endl;
        }
        else 
        {
            std::cerr << "send error: " << e.message() << std::endl;
        }

        i ++;
    }
}

int main(int ac, char* av[])
{
    if (ac != 4)
    {
        std::cout << "ac != 4" << std::endl;
        return -1;
    }

    if (std::string(av[1]) == "c")
    {
        test_udp_client(std::string(av[2]), std::string(av[3]));
    }
    else if (std::string(av[1]) == "s")
    {
        test_udp_server(std::string(av[2]), std::string(av[3]));
    }
    else
    {
        std::cout << "av[1] != \"c\" and av[1] != \"s\"" << std::endl;
        return -1;
    }
}

完成它,然后像这样运行:

./main s fe80::211:85ff:fe6c:44ac%eth0 100  #server, "s" means server,  
                                            #"fe80::211:85ff:fe6c:44ac%eth0" means your ipv6 address
                                            #and 100 is port
./main c fe80::211:85ff:fe6c:44ac 100       #run it in another ssh or shell

但结果是:

- 1 udp 服务器从不接收客户端发送的消息

[root@wangsu Tmp2]# ls<br>
main  main.cpp  main.o  Makefile<br>
[root@wangsu Tmp2]# ./main s fe80::211:85ff:fe6c:44ac%eth0 100<br>
address:fe80::211:85ff:fe6c:44ac%eth0 port:100<br>

2个udp客户端,已成功发送消息

[root@wangsu Tmp2]# ./main c fe80::211:85ff:fe6c:44ac 100<br>
send: udp message 0<br>
send: udp message 1<br>
send: udp message 2<br>
send: udp message 3<br>
send: udp message 4<br>
send: udp message 5<br>
send: udp message 6<br>
send: udp message 7<br>
send: udp message 8<br>
send: udp message 9<br>

3 当我打开 tcpdum 时,它确实捕获了客户端发送的消息

[root@wangsu Tmp2]# tcpdump -i lo udp and host fe80::211:85ff:fe6c:44ac<br>
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode<br>
listening on lo, link-type EN10MB (Ethernet), capture size 96 bytes<br>
10:55:41.215110 IP6 fe80::211:85ff:fe6c:44ac.59007 > fe80::211:85ff:fe6c:44ac.100: UDP, length 13<br>
10:55:41.215295 IP6 fe80::211:85ff:fe6c:44ac.59007 > fe80::211:85ff:fe6c:44ac.100: UDP, length 13<br>
10:55:41.215360 IP6 fe80::211:85ff:fe6c:44ac.59007 > fe80::211:85ff:fe6c:44ac.100: UDP, length 13<br>
10:55:41.215431 IP6 fe80::211:85ff:fe6c:44ac.59007 > fe80::211:85ff:fe6c:44ac.100: UDP, length 13<br>
10:55:41.215516 IP6 fe80::211:85ff:fe6c:44ac.59007 > fe80::211:85ff:fe6c:44ac.100: UDP, length 13<br>
10:55:41.215585 IP6 fe80::211:85ff:fe6c:44ac.59007 > fe80::211:85ff:fe6c:44ac.100: UDP, length 13<br>
10:55:41.215790 IP6 fe80::211:85ff:fe6c:44ac.59007 > fe80::211:85ff:fe6c:44ac.100: UDP, length 13<br>
10:55:41.215926 IP6 fe80::211:85ff:fe6c:44ac.59007 > fe80::211:85ff:fe6c:44ac.100: UDP, length 13<br>
10:55:41.216069 IP6 fe80::211:85ff:fe6c:44ac.59007 > fe80::211:85ff:fe6c:44ac.100: UDP, length 13<br>
10:55:41.216130 IP6 fe80::211:85ff:fe6c:44ac.59007 > fe80::211:85ff:fe6c:44ac.100: UDP, length 13<br>

4 这是我的 ifconfig:

[root@wangsu Tmp2]# ifconfig<br>
eth0      Link encap:Ethernet  HWaddr 00:11:85:6C:44:AC  
          inet addr:192.168.23.38  Bcast:192.168.23.255  Mask:255.255.255.0<br>
          inet6 addr: fe80::211:85ff:fe6c:44ac/64 Scope:Link<br>
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1<br>
          RX packets:1174940938 errors:0 dropped:0 overruns:0 frame:0<br>
          TX packets:626463551 errors:0 dropped:0 overruns:0 carrier:0<br>
          collisions:0 txqueuelen:100<br> 
          RX bytes:378565405153 (352.5 GiB)  TX bytes:126427805747 (117.7 GiB)<br>
          Base address:0x3400 Memory:fd000000-fd020000<br> 

lo        Link encap:Local Loopback 
          inet addr:127.0.0.1  Mask:255.0.0.0<br>
          inet6 addr: ::1/128 Scope:Host<br>
          inet6 addr: ::127.0.0.1/0 Scope:Compat<br>
          UP LOOPBACK RUNNING  MTU:16436  Metric:1<br>
          RX packets:188781410 errors:0 dropped:0 overruns:0 frame:0<br>
          TX packets:188781410 errors:0 dropped:0 overruns:0 carrier:0<br>
          collisions:0 txqueuelen:0<br> 
          RX bytes:582726106596 (542.7 GiB)  TX bytes:582726106596 (542.7 GiB)<br>

顺便说一下,在运行服务器和客户端之前,我已经停止了 iptables。更奇怪的是,在我的另一台电脑上它运行正常。

为什么?

最佳答案

除了我的评论中提供的解决方案外,也许您应该尝试允许您绑定(bind)到特定接口(interface)的类似解决方案。

我认为,问题在于您对主机和端口执行 DNS 查询,而您应该直接绑定(bind)到主机地址和端口。

像这样:

// First convert the address string to its binary form
boost::asio::ip::address_v6 address =
    boost::asio::ip::address_v6::from_string(host_);

// Create the endpoint
boost::asio::ip::udp::endpoint endpoint(address, atoi(port_.c_str()));

// And finally create a bound socket
boost::asio::ip::udp::socket socket(io_service, endpoint);

关于c++ - 在 ipv6 链接范围单播 udp 客户端-服务器守护进程中应用 boost::asio::ip::udp,有时有效,但有时无效,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11999922/

相关文章:

c++ - 是否可以从 log4j 或 log4cxx 等文件配置 spdlog?

c++ - 创建自己的 Boost::Archive 实现

c++ - 为什么 >16KB 的有效负载大小会导致吞吐量(TCP + TLS)大幅下降?

c++ - 在 C++ 中使用指向成员函数的函数指针数组

c++ - 检查是否至少设置了一点而不跳转

c++ - Qt 应用程序中的 boost 定时器

c++ - 在所有线程未完成时 boost 线程打印一些东西

c++ - boost - ASIO 与 IOStreams TCP

c++ - 使用 boost::async_connect 问题

c++ - += C++ 中的运算符