Boost buffer_cast 无法从 void* 转换为 PointerToPodType
Posted
技术标签:
【中文标题】Boost buffer_cast 无法从 void* 转换为 PointerToPodType【英文标题】:Boost buffer_cast cannot convert from void* to PointerToPodType 【发布时间】:2020-06-30 13:18:15 【问题描述】:我对 Socket 通信和使用 boost 库很感兴趣。当我收到来自服务器的消息并尝试将其转换为atomic<uint8_t>*
时,它给了我一个错误'static_cast': cannot convert from 'const void*' to 'PointerToPodType'
。我不明白为什么它给了我这个错误。
代码示例
atomic<uint8_t>* buffer = new atomic<uint8_t>[10000];
boost::asio::streambuf receive_buffer;
boost::asio::read(*sock, receive_buffer, boost::asio::transfer_all(), this->ec);
if (this->ec && this->ec != boost::asio::error::eof)
cout << "receive failed:" << this->ec.message() << endl;
else
///ERROR IS HERE
buffer = boost::asio::buffer_cast< atomic<uint8_t>*>(receive_buffer.data());
【问题讨论】:
【参考方案1】:不是C,不要使用new
、malloc
(或delete
或free
)。
具体来说,我看到了指向套接字的指针,指向一切的指针。如果您完成了分配工作,您会泄漏使用new
分配的整个缓冲区。
这是一个更简单的方法,减少双缓冲(streambuf
增加一点):
uint8_t buffer[10000];
auto transferred = boost::asio::read(
sock,
boost::asio::buffer(buffer),
boost::asio::transfer_all(),
ec);
现在成功后,tranferred
字节将在您分配的缓冲区中。更简单的
std::vector<uint8_t> buffer(10000);
因为这样你就可以简单地
buffer.resize(transferred);
Live On Coliru
#include <boost/asio.hpp>
#include <atomic>
#include <iostream>
#include <iomanip>
using boost::asio::ip::tcp;
using boost::asio::ip::address_v4;
int main()
//uint8_t buffer[10000];
std::vector<uint8_t> buffer(10000);
boost::asio::io_context ioc;
tcp::socket sock(ioc);
sock.connect(address_v4::from_string("173.203.57.63"), 80);
write(sock, boost::asio::buffer("GET / HTTP/1.1\r\nHost: coliru.stacked-crooked.com\r\nConnection: close\r\n\r\n"));
boost::system::error_code ec;
auto transferred = boost::asio::read(
sock,
boost::asio::buffer(buffer),
boost::asio::transfer_all(),
ec);
if (ec && ec != boost::asio::error::eof)
std::cout << "receive failed:" << ec.message() << std::endl;
else
buffer.resize(transferred);
std::cout << std::hex << std::showbase << std::setfill('0');
int n = 0;
for (int i : buffer)
std::cout
<< std::setw(4) << i
<< " '" << char(std::isgraph(i)?i : '.') << "'"
<< (++n % 8? ' ':'\n');
打印
g++ -std=c++17 -O2 -Wall -pedantic -pthread main.cpp && ./a.out
0x48 'H' 0x54 'T' 0x54 'T' 0x50 'P' 0x2f '/' 0x31 '1' 0x2e '.' 0x31 '1'
0x20 '.' 0x32 '2' 0x30 '0' 0x30 '0' 0x20 '.' 0x4f 'O' 0x4b 'K' 0x20 '.'
00xd '.' 00xa '.' 0x43 'C' 0x6f 'o' 0x6e 'n' 0x74 't' 0x65 'e' 0x6e 'n'
0x74 't' 0x2d '-' 0x54 'T' 0x79 'y' 0x70 'p' 0x65 'e' 0x3a ':' 0x20 '.'
0x74 't' 0x65 'e' 0x78 'x' 0x74 't' 0x2f '/' 0x68 'h' 0x74 't' 0x6d 'm'
... 1100 lines snipped
0x20 '.' 0x20 '.' 0x7d '' 0x3b ';' 00xa '.' 0x3c '<' 0x2f '/' 0x73 's'
0x63 'c' 0x72 'r' 0x69 'i' 0x70 'p' 0x74 't' 0x3e '>' 00xa '.' 0x3c '<'
0x2f '/' 0x68 'h' 0x74 't' 0x6d 'm' 0x6c 'l' 0x3e '>' 00xa '.'
动态/堆分配
std::vector
已经进行了堆分配。如果您坚持原始 C 数组语义,请考虑 Live On Coliru:
auto buffer = std::make_unique<std::array<std::atomic<uint8_t, 10'000> > >();
// ...
boost::asio::buffer(*buffer),
// ...
size_t n = 0;
for (int i : *buffer)
if (n>=transferred) break;
std::cout
<< std::setw(4) << i
<< " '" << char(std::isgraph(i)?i : '.') << "'"
<< (++n % 8? ' ':'\n');
甚至Live On Coliru:
auto buffer = std::make_unique<uint8_t[]>(10'000);
// ...
boost::asio::buffer(buffer.get(), 10'000),
// ...
size_t n = 0;
for (auto it = buffer.get(); it <= buffer.get() + transferred; ++it)
std::cout
<< std::setw(4) << static_cast<int>(*it)
<< " '" << char(std::isgraph(*it)?*it : '.') << "'"
<< (++n % 8? ' ':'\n');
正如您所见,像这样使用“手动”缓冲区的操作更容易出错,但至少现在您没有内存泄漏。
【讨论】:
编译器没有报错,但是当我读取时,程序挂在读取函数上。如果我将读取更改为 async_read 它可以工作,但我不想用 async_read 更改它。 这意味着永远不会结束?您正在专门等待另一端“挂断”(transfer_all
)。尝试使用transfer_exactly(somesmallnumber)
或只使用一个小缓冲区。在这种情况下,当缓冲区已满或请求的字节数已传输时,调用也将返回。当然,如果另一端从不发送响应......你仍然会等待。 (这就是为什么我使用 HTTP 请求来“强制”响应,并使用“Connection: close”标头)
读取功能是否在打开时获取每个字节?天哪,我认为 read 函数就像 winsock2.h 中的 recv 函数
transfer_all
有点说明了一切 :) 你甚至检查了预期的eof
条件...socket.read_some
更像那样,但话又说回来,这是降级到 C-land再次。你为什么要?实际上,您想要传输某种协议。因此,请考虑 boost::asio::read_until
以匹配您的协议框架。以上是关于Boost buffer_cast 无法从 void* 转换为 PointerToPodType的主要内容,如果未能解决你的问题,请参考以下文章
将 boost 变体与包含 bool 输入的 std::functions 一起使用
无法使用 Boost Format() 从 wstring 转换