POSIX VTIME 和 read() 的行为

POSIX behaviour with VTIME and read()

花了几个小时在线研究后,我仍然不太清楚 VTIMEread(int fildes, void *buf, size_t nbyte); 如何协同工作。在我看来,一旦 read() 得到一个字节,它就会忽略 VTIMEVTIME 仅在未读取任何字节时才遵守。

如果我没看错,here 的解释似乎证实了这一点:

VMIN = 0 and VTIME > 0 This is a pure timed read. If data are available in the input queue, it's transferred to the caller's buffer up to a maximum of nbytes, and returned immediately to the caller. Otherwise the driver blocks until data arrives, or when VTIME tenths expire from the start of the call. If the timer expires without data, zero is returned. A single byte is sufficient to satisfy this read call, but if more is available in the input queue, it's returned to the caller. Note that this is an overall timer, not an intercharacter one.

有什么方法可以使 read() return 仅当 nbyte 已满足 VTIME到达最后一个字节后?

VTIMEread()这样的行为似乎有点奇怪。为什么它不在超时前尝试读取 nbytes

例如,在下面的代码中,read() 在 returned 之前不会等待 10 秒。如果没有写入发生,那么它就会发生。

int main (void) {

    int usbSerial;
    struct termios options;
    std::string port = "/dev/tty.usb001";


    usbSerial = open(port.c_str(), O_RDWR| O_NOCTTY | O_NONBLOCK);

    // Check if unopen
    if(usbSerial == -1) {
        printf("Error: Unable to open %s\n", port.c_str());
    }
    else { // Set to blocking
        fcntl(usbSerial, F_SETFL, 0);
        printf("Connection to serial device established.\n");
    }

    // Set port settings
    tcgetattr(usbSerial, &options); // read old port settings
    cfsetispeed(&options, B9600);
    cfsetospeed(&options, B9600);

    options.c_cflag &= ~PARENB;    // set no parity, 1 stop bit, data bits
    options.c_cflag &= ~CSTOPB;
    options.c_cflag &= ~CSIZE;
    options.c_cflag |= CS8;

    options.c_cflag     &=  ~CRTSCTS;           // no flow control.
    options.c_cflag     |=  CREAD | CLOCAL;     // turn on READ & ignore ctrl lines

    options.c_cc[VMIN]   =  0;
    options.c_cc[VTIME]  =  100;


    // Flush port and then apply new options
    tcflush(usbSerial, TCIOFLUSH);
    if (tcsetattr(usbSerial, TCSANOW, &options) != 0) {    // TCSANOW == make option change immediately
        printf("Error %i from tcsetattr.\n", errno);
    }

    // write
    unsigned char message[] = {0x03, 0x05, 0x01, 0x01, 0x04};
    ssize_t n = write(usbSerial, &message, sizeof(message)/sizeof(message[0]));


    unsigned char buffer[64] = {};
    tcdrain(usbSerial);


    ssize_t readChars = read(usbSerial, &buffer, 10);

    printf("Done.\n");

}

我相信你说的是对的:

It seems to me that as soon as read() gets a single byte, then it disregards VTIME.

Return read() 的值:

On success, the number of bytes read is returned (zero indicates end of file), and the file position is advanced by this number. It is not an error if this number is smaller than the number of bytes requested; this may happen for example because fewer bytes are actually available right now (maybe because we were close to end-of-file, or because we are reading from a pipe, or from a terminal), or because read() was interrupted by a signal. link

您可能需要循环,可能类似于(未测试):

int totalNeeded = 10;
int remaining   = 10;
while (remaining > 0){
    ssize_t readChars = read(usbSerial, &buffer[totalNeeded - remaining], remaining);
    if (readChars > 0){
        remaining -= readChars;
    }
    else{
        // handle error or EOF
    }
}

不确定您需要如何处理部分读取,尤其是因为 O_NONBLOCK,但我认为 VTIME 和 read() 之间的行为交互受 read() 支配。