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。
我正在编写程序以将 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。