std::cin.read() 读取流失败
std::cin.read() fails to read stream
我正在为浏览器扩展实现 native host。我围绕 std::cin
而不是 C 风格 getchar()
设计了我的实现
这里的问题是 std::cin
没有以二进制模式打开,这对基于 Windows 的主机有影响,因为 Chrome 浏览器不能很好地与 Windows 一起工作样式 \r\n
因此我必须以二进制模式阅读它。
要以二进制模式读取,我必须使用 _setmode(_fileno(stdin), _O_BINARY);
我的 IDE 找不到 _fileno
的定义,我发现解决方法是使用以下宏,
#if !defined(_fileno)
#define _fileno(__F) ((__F)->_file)
#endif
但是,我对这个宏没有足够的信心。我认为出了点问题,但我使用的是最新的 MinGW 编译器,不确定为什么没有定义它。
更新:这个功能似乎在 __STRICT_ANSI__
后面,我不知道如何禁用它。
无论如何,程序编译正常,浏览器启动它,当我从浏览器发送消息时,应用程序能够读取消息的长度,当它尝试读取内容时,std::cin.read()
操作不会向缓冲区向量插入任何内容,消息也不会以 null 终止,但我认为这不会导致问题。
我也尝试过在不阅读的情况下向浏览器发送一条虚拟消息,但它似乎冻结了浏览器。
#include <iostream>
#include <cstdio>
#include <string>
#include <vector>
#ifdef __WIN32
#include <fcntl.h>
#include <io.h>
#endif
#if !defined(_fileno)
#define _fileno(__F) ((__F)->_file)
#endif
enum class Platforms {
macOS = 1,
Windows = 2,
Linux = 3
};
Platforms platform;
#ifdef __APPLE__
constexpr Platforms BuildOS = Platforms::macOS;
#elif __linux__
constexpr Platforms BuildOS = Platforms::Linux;
#elif __WIN32
constexpr Platforms BuildOS = Platforms::Windows;
#endif
void sendMessage(std::string message) {
auto *data = message.data();
auto size = uint32_t(message.size());
std::cout.write(reinterpret_cast<char *>(&size), 4);
std::cout.write(data, size);
std::cout.flush();
}
int main() {
if constexpr(BuildOS == Platforms::Windows) {
// Chrome doesn't deal well with Windows style \r\n
_setmode(_fileno(stdin), _O_BINARY);
_setmode(_fileno(stdout), _O_BINARY);
}
while(true) {
std::uint32_t messageLength;
// First Four contains message legnth
std::cin.read(reinterpret_cast<char*>(&messageLength), 4);
if (std::cin.eof())
{
break;
}
std::vector<char> buffer;
// Allocate ahead
buffer.reserve(std::size_t(messageLength) + 1);
std::cin.read(&buffer[0], messageLength);
std::string message(buffer.data(), buffer.size());
sendMessage("{type: 'Hello World'}");
}
}
解决方案:
buffer.reserve(std::size_t(messageLength) + 1);
应该是
buffer.resize(std::size_t(messageLength) + 1);
或者我们可以在构造过程中使用
预先调整缓冲区大小
std::vector<char> buffer(messageLength +1);
问题解释:
buffer.reserve(std::size_t(messageLength) + 1);
保留容量但不更改 vector
的大小,所以技术上
std::cin.read(&buffer[0], messageLength);`
是非法的,在
std::string message(buffer.data(), buffer.size());`
buffer.size()
仍然是 0。
我正在为浏览器扩展实现 native host。我围绕 std::cin
而不是 C 风格 getchar()
这里的问题是 std::cin
没有以二进制模式打开,这对基于 Windows 的主机有影响,因为 Chrome 浏览器不能很好地与 Windows 一起工作样式 \r\n
因此我必须以二进制模式阅读它。
要以二进制模式读取,我必须使用 _setmode(_fileno(stdin), _O_BINARY);
我的 IDE 找不到 _fileno
的定义,我发现解决方法是使用以下宏,
#if !defined(_fileno)
#define _fileno(__F) ((__F)->_file)
#endif
但是,我对这个宏没有足够的信心。我认为出了点问题,但我使用的是最新的 MinGW 编译器,不确定为什么没有定义它。
更新:这个功能似乎在 __STRICT_ANSI__
后面,我不知道如何禁用它。
无论如何,程序编译正常,浏览器启动它,当我从浏览器发送消息时,应用程序能够读取消息的长度,当它尝试读取内容时,std::cin.read()
操作不会向缓冲区向量插入任何内容,消息也不会以 null 终止,但我认为这不会导致问题。
我也尝试过在不阅读的情况下向浏览器发送一条虚拟消息,但它似乎冻结了浏览器。
#include <iostream>
#include <cstdio>
#include <string>
#include <vector>
#ifdef __WIN32
#include <fcntl.h>
#include <io.h>
#endif
#if !defined(_fileno)
#define _fileno(__F) ((__F)->_file)
#endif
enum class Platforms {
macOS = 1,
Windows = 2,
Linux = 3
};
Platforms platform;
#ifdef __APPLE__
constexpr Platforms BuildOS = Platforms::macOS;
#elif __linux__
constexpr Platforms BuildOS = Platforms::Linux;
#elif __WIN32
constexpr Platforms BuildOS = Platforms::Windows;
#endif
void sendMessage(std::string message) {
auto *data = message.data();
auto size = uint32_t(message.size());
std::cout.write(reinterpret_cast<char *>(&size), 4);
std::cout.write(data, size);
std::cout.flush();
}
int main() {
if constexpr(BuildOS == Platforms::Windows) {
// Chrome doesn't deal well with Windows style \r\n
_setmode(_fileno(stdin), _O_BINARY);
_setmode(_fileno(stdout), _O_BINARY);
}
while(true) {
std::uint32_t messageLength;
// First Four contains message legnth
std::cin.read(reinterpret_cast<char*>(&messageLength), 4);
if (std::cin.eof())
{
break;
}
std::vector<char> buffer;
// Allocate ahead
buffer.reserve(std::size_t(messageLength) + 1);
std::cin.read(&buffer[0], messageLength);
std::string message(buffer.data(), buffer.size());
sendMessage("{type: 'Hello World'}");
}
}
解决方案:
buffer.reserve(std::size_t(messageLength) + 1);
应该是
buffer.resize(std::size_t(messageLength) + 1);
或者我们可以在构造过程中使用
预先调整缓冲区大小std::vector<char> buffer(messageLength +1);
问题解释:
buffer.reserve(std::size_t(messageLength) + 1);
保留容量但不更改 vector
的大小,所以技术上
std::cin.read(&buffer[0], messageLength);`
是非法的,在
std::string message(buffer.data(), buffer.size());`
buffer.size()
仍然是 0。