来自 boost::asio::ip::tcp::socket 个奇怪行为的字符串
String from boost::asio::ip::tcp::socket weird behaviour
我正在尝试实现一个使用 C++ 套接字的应用程序。我正在尝试从套接字中读取字符串,但遇到了各种各样的问题。在main函数中获取不到字符串,但是在函数中可以获取到。谁能指出我正确的方向?
这是我的代码:
int main(int argc, char *argv[]) {
try {
asio::io_context io_context;
tcp::acceptor acceptor(io_context, tcp::endpoint(tcp::v4(), 8080));
tcp::socket socket(io_context);
printf("Accepting...\n");
acceptor.accept(socket);
for (;;)
{
std::string message = read_(socket);
printf("Message: %s\n", message);
}
} catch (std::exception& e) {
printf(e.what());
}
}
std::string read_(tcp::socket & socket) {
asio::streambuf buf;
asio::read_until( socket, buf, "\n" );
const unsigned char* data = asio::buffer_cast<const unsigned char*>(buf.data());
std::string result((char*)data);
printf("Text: %s, and length: %d\n", result, result.length());
printf("Text casted: %s\n", data);
return result;
}
这是我通过套接字发送字符串“test”后的输出:
Accepting...
Text: ♀²w, and length: 6
Text casted: test
Message: ░■w
printf 不将 std::string 作为参数。由于 printf 不是类型安全的并且是可变参数函数,这就是它编译并且不给出任何错误的原因。将 std::string 传递给它将是未定义的行为。
要么使用std::cout,要么使用std::string的c_str方法。
是的,正如其他人所指出的,printf
不适用于 std::string
。您可以轻松解决它,但编写 C++ 代码也许是个好主意:
std::cout << "Message: " << message << "\n";
// ...
std::cout << "Text: " << result << ", and length: " << result.length()
<< "\n";
std::cout << "Text casted: " << data << "\n";
除此之外,还有...问题。您有一个从 unsigned char const*
到 char*
的 C 风格转换。 C 风格的转换很危险,因为它们最终会变成 reinterpret_cast
-ing。在这种情况下,您错误地(并且不必要地)丢弃了 const
.
为什么不只是 buffer_cast 到所需的类型呢?
auto data = asio::buffer_cast<char const*>(buf.data());
std::string result(data);
这给我们带来了下一个问题:您假设数据以 NUL 结尾 并且 不包含任何嵌入的 NUL 字符。更好的方法是使用 asio::read_until
中的 return 值(你忽略了):
auto length = asio::read_until(socket, buf, "\n");
auto data = asio::buffer_cast<char const*>(buf.data());
std::string result(data, data + length);
话虽这么说,但我不相信您可以在没有进一步准备的情况下使用 streambuf
就好像是连续的。为什么不使用缓冲区迭代器来确保您不会误解任何实现细节:
asio::streambuf buf;
/*auto length =*/asio::read_until(socket, buf, "\n");
std::string const result(buffers_begin(buf.data()),
buffers_end(buf.data()));
请注意,这会立即消除忘记长度的“问题”。
小费
为什么不读入一个字符串,节省副本和复杂性:
std::string result;
asio::read_until(socket, asio::dynamic_buffer(result), "\n");
固定
#include <boost/asio.hpp>
#include <iostream>
namespace asio = boost::asio;
using asio::ip::tcp;
std::string read_(tcp::socket& socket);
int main()
{
try {
asio::io_context io_context;
tcp::acceptor acceptor(io_context, {{}, 6768});
tcp::socket socket(io_context);
std::cout << "Accepting...\n";
acceptor.accept(socket);
for (;;)
{
std::string message = read_(socket);
std::cout << "Message: " << message << "\n";
}
} catch (std::exception& e) {
std::cout << e.what() << "\n";
}
}
std::string read_(tcp::socket& socket)
{
std::string result;
asio::read_until(socket, asio::dynamic_buffer(result), "\n");
return result;
}
有
我正在尝试实现一个使用 C++ 套接字的应用程序。我正在尝试从套接字中读取字符串,但遇到了各种各样的问题。在main函数中获取不到字符串,但是在函数中可以获取到。谁能指出我正确的方向?
这是我的代码:
int main(int argc, char *argv[]) {
try {
asio::io_context io_context;
tcp::acceptor acceptor(io_context, tcp::endpoint(tcp::v4(), 8080));
tcp::socket socket(io_context);
printf("Accepting...\n");
acceptor.accept(socket);
for (;;)
{
std::string message = read_(socket);
printf("Message: %s\n", message);
}
} catch (std::exception& e) {
printf(e.what());
}
}
std::string read_(tcp::socket & socket) {
asio::streambuf buf;
asio::read_until( socket, buf, "\n" );
const unsigned char* data = asio::buffer_cast<const unsigned char*>(buf.data());
std::string result((char*)data);
printf("Text: %s, and length: %d\n", result, result.length());
printf("Text casted: %s\n", data);
return result;
}
这是我通过套接字发送字符串“test”后的输出:
Accepting...
Text: ♀²w, and length: 6
Text casted: test
Message: ░■w
printf 不将 std::string 作为参数。由于 printf 不是类型安全的并且是可变参数函数,这就是它编译并且不给出任何错误的原因。将 std::string 传递给它将是未定义的行为。
要么使用std::cout,要么使用std::string的c_str方法。
是的,正如其他人所指出的,printf
不适用于 std::string
。您可以轻松解决它,但编写 C++ 代码也许是个好主意:
std::cout << "Message: " << message << "\n";
// ...
std::cout << "Text: " << result << ", and length: " << result.length()
<< "\n";
std::cout << "Text casted: " << data << "\n";
除此之外,还有...问题。您有一个从 unsigned char const*
到 char*
的 C 风格转换。 C 风格的转换很危险,因为它们最终会变成 reinterpret_cast
-ing。在这种情况下,您错误地(并且不必要地)丢弃了 const
.
为什么不只是 buffer_cast 到所需的类型呢?
auto data = asio::buffer_cast<char const*>(buf.data());
std::string result(data);
这给我们带来了下一个问题:您假设数据以 NUL 结尾 并且 不包含任何嵌入的 NUL 字符。更好的方法是使用 asio::read_until
中的 return 值(你忽略了):
auto length = asio::read_until(socket, buf, "\n");
auto data = asio::buffer_cast<char const*>(buf.data());
std::string result(data, data + length);
话虽这么说,但我不相信您可以在没有进一步准备的情况下使用 streambuf
就好像是连续的。为什么不使用缓冲区迭代器来确保您不会误解任何实现细节:
asio::streambuf buf;
/*auto length =*/asio::read_until(socket, buf, "\n");
std::string const result(buffers_begin(buf.data()),
buffers_end(buf.data()));
请注意,这会立即消除忘记长度的“问题”。
小费
为什么不读入一个字符串,节省副本和复杂性:
std::string result;
asio::read_until(socket, asio::dynamic_buffer(result), "\n");
固定
#include <boost/asio.hpp>
#include <iostream>
namespace asio = boost::asio;
using asio::ip::tcp;
std::string read_(tcp::socket& socket);
int main()
{
try {
asio::io_context io_context;
tcp::acceptor acceptor(io_context, {{}, 6768});
tcp::socket socket(io_context);
std::cout << "Accepting...\n";
acceptor.accept(socket);
for (;;)
{
std::string message = read_(socket);
std::cout << "Message: " << message << "\n";
}
} catch (std::exception& e) {
std::cout << e.what() << "\n";
}
}
std::string read_(tcp::socket& socket)
{
std::string result;
asio::read_until(socket, asio::dynamic_buffer(result), "\n");
return result;
}
有