BOOST UDP问题

BOOST UDP issue

我正在编写程序以将 BOOST 库用于 UDP 协议。我只在 windows 上发生错误,它在 CentOS 6.9 (Linux) GCC 上工作正常。

问题是 - 当我使用send_to函数在特定IP或端口的套接字上写入数据并假设IP/PORT 不工作,然后并行读取套接字通知我们它有数据可供读取。当我读取该数据时,它的长度 = -1 使用本机套接字。

例子:假设对于这个UDP,Server PORT为9000,client PORT为6000,client端口不工作,强行发送数据报包(UDP包) 从 9000(服务器)到 6000(客户端)。在这里,在读取套接字上我们有数据及其 length = -1

这里,问题:为什么9000(Server)socket刚写完socket就有数据要读,读的时候长度为-1。

所以,如果有人对此问题有解决方案,请讨论。

示例代码如下:

#include "stdafx.h"
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#define _WINSOCK_DEPCRECATED

#include "WinSock2.h"

#include <boost/asio.hpp>
using boost::asio::ip::udp;

boost::asio::io_service m_ioService;

bool DoesSocketHaveAnyData(udp::socket *m_lpSocket)
{

    // set the timeout to UDP_MILLISEC_WAIT_FOR_DATA seconds
    struct timeval tv;
    tv.tv_sec = 0;
    //tv.tv_usec = 1000 * 1000 * 20;    // UDP_MILLISEC_WAIT_FOR_DATA;
    tv.tv_usec = 1;                     // UDP_MILLISEC_WAIT_FOR_DATA;

    // We'll need to get the underlying native socket for this select call, in order to add a simple timeout on the read:
    int nativeSocket = (int)m_lpSocket->native_handle();

    fd_set fileDescriptorSet;
    FD_ZERO(&fileDescriptorSet);
    FD_SET(nativeSocket, &fileDescriptorSet);

    bool m_blnCheck = false;

    //Wait for message until timeout expires
    if (select(nativeSocket + 1, &fileDescriptorSet, NULL, NULL, &tv) == 0)
    {
        m_blnCheck = false;
    }
    else
    {
        if (!FD_ISSET(nativeSocket, &fileDescriptorSet)) 
        {
            m_blnCheck = false;
        }
        else
        {
            //Issue arise here -> Receice data here, upon checking length -1 (initially, sending data buffer to specific remote endpoint).


            //==> Way 1
            /*//boost::system::error_code ee;
            //size_t tt = m_lpSocket->available(ee);
            size_t m_availableNoOfBytes = m_lpSocket->available();
            if (m_availableNoOfBytes >= 2) { m_blnCheck = true; }*/

            //==> Way 2
            struct sockaddr_in src_addr;    /* Used to receive (addr,port) of sender */
            int src_addr_len;               /* Length of src_addr */
            int len;                        /* Length of result from nativeSocket */
            char line[BUFSIZ * 2] = { 0 };

            src_addr_len = sizeof(src_addr);

            len = recvfrom(nativeSocket, line, BUFSIZ * 2, MSG_PEEK /* flags */, (struct sockaddr *) &src_addr, &src_addr_len);
            /*printf("Msg from (%u,%u): `%s' (%u bytes)\n", src_addr.sin_addr.s_addr, src_addr.sin_port, line, len);*/

            if (len > 0)
            {
                m_blnCheck = true;
            }
            else
            {
                len = recvfrom(nativeSocket, line, BUFSIZ * 2, 0 /* flags */, (struct sockaddr *) &src_addr, &src_addr_len);
            }
        }
    }

    return m_blnCheck;
}


int main()
{
    int m_uiMyPortNumber = 9000;

    try {
        //boost::asio::ip::udp::endpoint boostEndPoint(boost::asio::ip::udp::v4(), m_uiMyPortNumber);
        udp::endpoint boostEndPoint(boost::asio::ip::address::from_string("192.168.1.117"), m_uiMyPortNumber);
        udp::socket *m_lpSocket = new udp::socket(m_ioService, boostEndPoint);


        bool blnCheck = false;
        do {

            m_lpSocket->set_option(boost::asio::socket_base::reuse_address(true));
            m_lpSocket->set_option(boost::asio::socket_base::broadcast(true));
            m_lpSocket->set_option(boost::asio::socket_base::do_not_route(true));

            boost::system::error_code error_obj;
            boost::asio::ip::udp::endpoint remote_endpoint(boost::asio::ip::address::from_string("192.168.1.121"), 6000);


            /////////////////////////////////////////////////////////////////////////////////////////////////////////////
            //Issue arise here -> Sending data buffer to specific remote endpoint. Also, "remote endpoint" is not having opened UDP port.

            //=> Way 1: using boost 
            size_t  m_sendto = m_lpSocket->send_to(boost::asio::buffer((char *)"TEST", 4), remote_endpoint, 0, error_obj);
            if (error_obj) { return false; }


            //=> Way 2: using native socket
            /*struct sockaddr_in si_other;

            si_other.sin_family = AF_INET;
            si_other.sin_port = htons(6000);            

            #ifdef _WIN32_WINNT 0x0501
                        si_other.sin_addr.s_addr = inet_addr("192.168.1.121"); //for XP
            #else
                        inet_pton(AF_INET, "192.168.1.121", &inaddr.sin_addr.s_addr); //for Vista or higher
            #endif

            size_t m_sendto = sendto(m_lpSocket->native_handle(), (char *)"TEST", 4, 0, (struct sockaddr*) &si_other, sizeof(si_other));*/

            blnCheck = DoesSocketHaveAnyData(m_lpSocket);

        } while (blnCheck == false);

        printf("success\n");

    }
    catch (boost::system::system_error const &e) 
    {
        printf("%s\n", e.what());
    }

    getchar();
    return 0;
}

如果一个 UDP 数据包被发送到一个没有套接字来处理这个数据包的目的地,那么(通常)一个 ICMP 不可达消息将被发送到原始源 IP。如果在那里收到,它将在发送方套接字上设置一个标志,以便通过下一个套接字操作将问题传递给应用程序,即下一个发送或接收将失败。

在实践中,目标可能不会发送无法到达的 ICMP(已禁用或速率受限),或者目标上的防火墙、目标上或两者之间的某处可能会阻止无法到达的 ICMP 被传送 - 实际上并不少见一般阻止 ICMP。在这些情况下,发件人将不会收到 ICMP 无法访问的消息,也无法将错误传播到应用程序。

因此,您的情况可能有所不同,在某些情况下,ICMP 无法到达在到达原始发件人之前会被阻止,而在其他情况下则不会。

有关详细信息,另请参阅 boost::asio error for UDP async_receive and UDP socket fail to receive ECONNREFUSED