簡體   English   中英

linux偽終端(打開select讀取)

[英]linux pseudo terminal (open select read)

我有以下場景:有人通過打開 /dev/ptmx 創建了一個偽終端。 新終端已創建並命名,例如 /dev/pts/2。 然后,在我的程序中,我打開 /dev/pts/2 進行閱讀。 但我也打開其他設備進行讀取並使用select() function 等待任何傳入數據。 select 還指定了一些超時,用於在沒有數據到達太長時間時執行其他操作。 成功 select 后,我使用read() function 讀取數據,然后將其打印在屏幕上。

如果偽終端被創建它的人關閉,我遇到了一個問題。 在這種情況下select function 立即結束,指示成功, read結束則通過返回零指示“無數據”。 恕我直言,在這種情況下,select 和 read 都不會返回錯誤。 我應該如何處理以檢測終端不再存在?

    Status processData()
    {
        fd_set readFileDescriptorSet; // defined somewhere else
        int maxFileDescriptor; // defined somewhere else
        struct timeval timeout; // defined somewhere else
      
        int ret = select(maxFileDescriptor + 1, &readFileDescriptorSet, nullptr, nullptr, &timeout);
        if (!ret) // timeout
            return Status::success();
        if (ret < 0) // error from select()
            return Status::error("select error");

        ssize_t rd;
        char buff[10];
        do {
            rd = read(interfaces.serialPort.getFileDescriptor(), buff, sizeof(buff) - 1);
            if (rd > 0) { // some data has been read
                buff[rd] = '\0';
                std::cout << buff;
            }
        } while (rd > 0);
        if (rd < 0) // error from read()
            return Status::error("read error");

        return Status::success();
    }

雖然我打開偽終端的方式如下:

    Status internalOpen(std::string fileName)
    {
        close();

        fileDescriptor = ::open(fileName.c_str(), O_RDWR | O_NOCTTY | O_NONBLOCK);
        if (fileDescriptor == -1)
            return Status::error("Terminal::internalOpen::open('" + fileName + "')");

        struct termios attributes;
        if (tcgetattr(fileDescriptor, &attributes))
            return Status::error("Terminal::internalOpen::tcgetattr()");

        setAttributes(attributes);

        if (tcsetattr(fileDescriptor, TCSANOW, &attributes))
            return Status::error("Terminal::internalOpen::tcsetattr()");

        return Status::success();
    }

    void setAttributes(struct termios &attributes)
    {
        cfmakeraw(&attributes);
        cfsetspeed(&attributes, Config::baudRate);
        attributes.c_iflag &= ~(IXOFF | IXANY);
        attributes.c_oflag &= ~(ONLCR);
        attributes.c_lflag &= ~(ECHOE);
        attributes.c_cflag &= ~(CSTOPB | CRTSCTS);
        attributes.c_cflag |= CREAD | CLOCAL;
        attributes.c_cc[VMIN] = 0;
        attributes.c_cc[VTIME] = 0;
    }

select()返回指示有要讀取的內容后,顯示的代碼循環重復嘗試從非阻塞文件描述符中read()直到它為 0:

    do {
        rd = read( ...
    } while (rd > 0);

這當然是合理的。 除了關閉的連接導致第一個read()返回 0,顯示的邏輯無法區分。

這里真正需要的是跟蹤是否已讀取任何內容,之前的read()返回 0。但是如果read()立即返回 0,那么你的鵝就熟了。

此外,還有一些其他改進將使事情變得更加強大。

  1. select()返回后,實際檢查文件描述符的位是否在readFileDescriptorSet中保持設置。 通過檢查所有其他可能性,顯示的邏輯只是假設它是。 不過,這有點脆弱。 如果某些切向相關的內容被修改(即,另一個文件描述符被混入其中),很容易忘記這個假設。
  2. 使用poll()而不是select() ,並在 revents 中明確檢查POLLHUP|POLLRDHUP revents poll()接口中更明確地調用了文件描述符關閉條件。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM