【问题标题】:Cannot read from pseudoterminal无法从伪终端读取
【发布时间】:2017-05-06 10:34:55
【问题描述】:

我编写了一个高级包装器和命令集合,它使用 RProc/RPMsg 接口与微处理器通信,为了尽可能多地进行测试,我已经为它编写了单元测试,使用 Linux 伪终端“真实”界面的位置。

我的测试没有成功。我最终将测试简化到不包含我的代码痕迹的地步——但它仍然不起作用:

BOOST_AUTO_TEST_CASE(constructor)
{
    const auto master_pty = ::posix_openpt(O_RDWR);
    BOOST_REQUIRE(master_pty != -1);
    BOOST_REQUIRE(::grantpt(master_pty) != -1);
    BOOST_REQUIRE(::unlockpt(master_pty) != -1);

    const auto slave_pty_name = ::ptsname(master_pty);
    const auto slave_pty = ::open(slave_pty_name, O_RDWR);
    BOOST_REQUIRE(slave_pty != -1);

    const auto in_data = std::array<std::uint8_t, 4>{1, 2, 3, 4};
    const auto bytes_written = ::write(master_pty, in_data.data(), in_data.size());
    if (bytes_written < 0) {
        BOOST_FAIL("Failed to write: " << errno);
    }
    BOOST_REQUIRE_EQUAL(in_data.size(), bytes_written);

    auto out_data = std::array<std::uint8_t, in_data.size()>{};
    const auto bytes_read = ::read(slave_pty, out_data.data(), out_data.size());
    BOOST_CHECK_EQUAL(bytes_read, bytes_written);
    if (bytes_read < 0) {
        BOOST_FAIL("::read failed: " << errno);
    }

    ::close(slave_pty);
    ::close(master_pty);
}

其输出为:

*** 1 failure is detected in the test module "cmPTP Test Suite"
# cmPTP-manager-test -l all --run_test=comms_rproc_interface/constructor
Running 1 test case...
Entering test module "cmPTP Test Suite"
interface_test.cpp(17): Entering test suite "comms_rproc_interface"
interface_test.cpp(19): Entering test case "constructor"
interface_test.cpp(23): info: check master_pty != -1 has passed
interface_test.cpp(24): info: check grantpt(master_pty) != -1 has passed
interface_test.cpp(25): info: check unlockpt(master_pty) != -1 has passed
interface_test.cpp(32): info: check slave_pty != -1 has passed
interface_test.cpp(72): info: check in_data.size() == bytes_written has passed
interface_test.cpp(77): error: in "comms_rproc_interface/constructor": check bytes_read == bytes_written has failed [0 != 4]
interface_test.cpp(19): Leaving test case "constructor"; testing time: 15282us
interface_test.cpp(17): Leaving test suite "comms_rproc_interface"; testing time: 15931us
Leaving test module "cmPTP Test Suite"; testing time: 16879us

*** 1 failure is detected in the test module "cmPTP Test Suite"

我可以很好地写入我的 4 个字节,但从属端没有任何内容。为什么?

【问题讨论】:

  • 这看起来不像读取实际上失败了,但它没有检索字节。写入缓冲区是否已刷新?
  • @starturtle 应该有:“POSIX 要求可以证明在 write() 返回后发生的 read(2) 返回新数据。请注意,并非所有文件系统都符合 POSIX。 "我当然假设 Linux/EXT4 符合 POSIX 标准……如何强制刷新?
  • @starturtle 实际上,我刚刚意识到 PTS 是 两个 文件描述符,因此上述内容不适用。
  • 我的问题得到了回答 here - open 没有缓冲,所以没有缓冲区可以刷新。鉴于它是一个与系统相关的函数,我认为假设它对 C 和 C++ 的行为相同是安全的。
  • @starturtle 我发现我做错了什么,这与冲洗有关。看我的回答。

标签: c++ linux terminal boost-test


【解决方案1】:

这是因为我忘记了我创建的是伪终端,而不是串行设备。 PTY 将我的输入值视为 ASCII(这可能有点吓坏了),并且在刷新之前等待换行 - 所以@starturtle 关于刷新的评论是正确的,只是不是“正常”的文件写入方式.

这个简单的 SSCCE 展示了我应该如何做到这一点:

#include <unistd.h>
#include <pty.h>

#include <array>
#include <iostream>

int main()
{
    // Make the PTY 'raw' to disable traditional terminal-like
    // behaviour
    struct termios ts;
    cfmakeraw(&ts);

    auto master_pty = -1;
    auto slave_pty  = -1;
    if (::openpty(&master_pty, &slave_pty, nullptr, &ts, nullptr) < 0) {
        std::cerr << "Cannot create PTY: " << errno << std::endl;
        return EXIT_FAILURE;
    }

    const auto in_data = std::array<std::uint8_t, 5>{1, 2, 3, 4, 5};
    const auto bytes_written = ::write(master_pty, in_data.data(), in_data.size());
    if (bytes_written < 0) {
        std::cerr << "Failed to write: " << errno << std::endl;
        return EXIT_FAILURE;
    }

    auto out_data = std::array<std::uint8_t, in_data.size()>{};
    out_data.fill(0);

    const auto bytes_read = ::read(slave_pty, out_data.data(), out_data.size());
    if (bytes_read < 0) {
        std::cerr << "::read failed: " << errno << std::endl;
        return EXIT_FAILURE;
    }

    for (auto&& c : out_data) {
        std::cout << static_cast<int>(c);
    }
    std::cout << std::endl;

    ::close(slave_pty);
    ::close(master_pty);
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多