[英]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,那么你的鵝就熟了。
此外,還有一些其他改進將使事情變得更加強大。
select()
返回后,實際檢查文件描述符的位是否在readFileDescriptorSet
中保持設置。 通過檢查所有其他可能性,顯示的邏輯只是假設它是。 不過,這有點脆弱。 如果某些切向相關的內容被修改(即,另一個文件描述符被混入其中),很容易忘記這個假設。poll()
而不是select()
,並在 revents 中明確檢查POLLHUP|POLLRDHUP
revents
在poll()
接口中更明確地調用了文件描述符關閉條件。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.