我正在编写将BOOST库用于UDP协议的程序。我仅在Windows上发生过错误,在CentOS 6.9(Linux)GCC上可以正常工作。
问题是 -当我使用send_to函数在特定IP或端口的套接字上写入数据并且假定IP / PORT无法正常工作时,则并行读取套接字通知我们认为它具有可供读取的数据。当我读取该数据时,使用本地套接字的长度为-1。
示例 :假设此UDP的服务器端口为9000,客户端端口为6000,客户端端口不起作用,并强制发送数据报包(UDP包) )从9000(服务器)到6000(客户端)。在这里,在读取套接字上,我们有数据及其 length = -1
在这里,问题:为什么9000(服务器)套接字在写入套接字后立即具有要读取的数据,但是在读取期间却有-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;
}
答案 0 :(得分:0)
如果将UDP数据包发送到没有套接字来处理该数据包的目标,则(通常)ICMP无法到达消息将发送到原始源IP。如果在那里收到,它将在发送方套接字上设置一个标志,以便在下一个套接字操作将问题传递给应用程序时,即下一个发送或接收将失败。
在实践中,目标可能不会发送无法到达的ICMP(禁用或速率受限),或者目标上,目的地或两者之间的某个位置的防火墙可能会阻止无法传递ICMP-阻止ICMP实际上并不罕见一般来说。在这种情况下,发件人将不会收到ICMP不可达消息,也无法将错误传播到应用程序。
因此,您的情况的不同之处可能是,在某些情况下,ICMP无法访问在到达原始发件人之前被阻止,而在其他情况下则没有。
有关更多信息,请参见boost::asio error for UDP async_receive和UDP socket fail to receive ECONNREFUSED。