字节未发送到串行驱动程序缓冲区
Bytes are not sent to the serial driver buffer
我有这个程序:
// C headers
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <stdint.h>
// POSIX headers
#include <unistd.h>
#include <sys/ioctl.h>
// Other headers
#include "ZL_sleep.h"
#include "ZL_utf8.h"
#include "ZL_serial.h"
#define BS 4 // Buffer size
int main(int argc, char * argv[]){
int32_t p; // Port
int32_t r; // Read finished
uint8_t b[BS]; // Buffer
uint32_t n; // Number of bytes to be read from driver buffer
if(argc != 2){
printf("ERROR: Supply a \"serial port\" device file.");
exit(EXIT_FAILURE);
}
p = ZL_open_tty(argv[1]);
if(p < 0){
perror("ERROR: open()");
exit(EXIT_FAILURE);
}
while(1){
memset(b, '[=10=]', BS);
r = read(p, b, BS);
if(r < 0){
if(errno == EAGAIN){
}
else{
perror("ERROR: read()");
close(p);
exit(EXIT_FAILURE);
}
}
ZL_utf8_print_bytes(b, BS);
putchar('\n');
}
close(p);
return EXIT_SUCCESS;
}
使用函数 ZL_utf8_print_bytes()
打印缓冲区字节 (在 for 循环中一个一个地打印)。它还调用函数 ZL_open_tty()
并将 argv[1]
(/dev/pts/1
) 作为参数传递给它。
函数 ZL_open_tty()
函数将 O_NONBLOCK
标志设置为 open()
,以便 open()
立即变为 return,即 “非阻塞”。 =60=] 什么状态。然后在使用任何其他 I/O 函数之前,函数清除 O_NONBLOCK
标志并切换回 “阻塞”。然后设置 VMIN
和 VTIME
以便 read()
:
blocks until VMIN
or more bytes is received/exists in driver
buffer. (It may block indefinitely)
uint32_t ZL_open_tty(const char * terminal){
uint32_t fd; // File's descriptor
uint32_t fl; // File's flags
struct termios fo; // File's options
fd = open(terminal, O_RDWR | O_NOCTTY | O_NONBLOCK);
if(fd < 0){
return -1;
}
fl = fcntl(fd, F_GETFL, 0);
if(fl < 0){
perror("ERROR: fcntl():");
return -1;
}
fcntl(fd, F_SETFL, fl & ~(O_NONBLOCK | O_APPEND | O_DSYNC | O_RSYNC | O_SYNC));
tcgetattr(fd, &fo);
fo.c_cc[VMIN] = 1;
fo.c_cc[VTIME] = 0;
tcsetattr(fd, TCSANOW, &fo);
fputs("─────────────────────────────────────────────────── terminal settings\n", stdout);
printf("VMIN = %d\n", fo.c_cc[VMIN]);
printf("VTIME = %d\n", fo.c_cc[VTIME]);
putchar('\n');
return(fd);
之后我的程序进入一个无限的 while 循环,其中 read()
阻塞,直到我在键盘焦点位于 /dev/pts/1
.[=35= 时输入任何键]
我面临的问题是有时我在 /dev/pts/1
中按下一个键,用这个键注册的字节没有传输到驱动程序缓冲区?!字节只停留在/dev/pts/1
。 ASCII(1 字节)字符和 UTF8(多字节)字节会发生这种情况...
我知道 read()
试图从驱动程序缓冲区中读取 请求的 字节数 (BS
)。但如果驱动程序缓冲区中没有 BS
字节可用,它会读取较少的字节。所以......如果一些字节稍后到达,它可以稍后读取它们。但是由于某种原因这些字节永远不会到达驱动程序缓冲区...
什么可能导致字节未到达驱动程序缓冲区并永远保留在 /dev/pts/1
中?
pts
是在虚拟终端连接到系统时创建的(通常是 ssh
)。 pts
连接为 stdin
/stdout
用于连接启动的 shell,因此您已经有一个进程附加到 pts
和读取来自它。
一旦你附加了你的应用程序,你就有效地开始了两个进程(你的应用程序和 shell)之间的竞争,所以谁更快谁就会收到缓冲区的内容。该字符并未保留在 pts
的缓冲区中,而是被附加到 pts
的 shell 读取。
为了能够不中断附加进程的读取,您需要通过通知主多路复用器 ptmx
来拦截 pts
的缓冲区,请参阅 ptmx(4). You can study how it's done in the interceptty[ 了解更多信息=21=]
我有这个程序:
// C headers
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <stdint.h>
// POSIX headers
#include <unistd.h>
#include <sys/ioctl.h>
// Other headers
#include "ZL_sleep.h"
#include "ZL_utf8.h"
#include "ZL_serial.h"
#define BS 4 // Buffer size
int main(int argc, char * argv[]){
int32_t p; // Port
int32_t r; // Read finished
uint8_t b[BS]; // Buffer
uint32_t n; // Number of bytes to be read from driver buffer
if(argc != 2){
printf("ERROR: Supply a \"serial port\" device file.");
exit(EXIT_FAILURE);
}
p = ZL_open_tty(argv[1]);
if(p < 0){
perror("ERROR: open()");
exit(EXIT_FAILURE);
}
while(1){
memset(b, '[=10=]', BS);
r = read(p, b, BS);
if(r < 0){
if(errno == EAGAIN){
}
else{
perror("ERROR: read()");
close(p);
exit(EXIT_FAILURE);
}
}
ZL_utf8_print_bytes(b, BS);
putchar('\n');
}
close(p);
return EXIT_SUCCESS;
}
使用函数 ZL_utf8_print_bytes()
打印缓冲区字节 (在 for 循环中一个一个地打印)。它还调用函数 ZL_open_tty()
并将 argv[1]
(/dev/pts/1
) 作为参数传递给它。
函数 ZL_open_tty()
函数将 O_NONBLOCK
标志设置为 open()
,以便 open()
立即变为 return,即 “非阻塞”。 =60=] 什么状态。然后在使用任何其他 I/O 函数之前,函数清除 O_NONBLOCK
标志并切换回 “阻塞”。然后设置 VMIN
和 VTIME
以便 read()
:
blocks until
VMIN
or more bytes is received/exists in driver buffer. (It may block indefinitely)
uint32_t ZL_open_tty(const char * terminal){
uint32_t fd; // File's descriptor
uint32_t fl; // File's flags
struct termios fo; // File's options
fd = open(terminal, O_RDWR | O_NOCTTY | O_NONBLOCK);
if(fd < 0){
return -1;
}
fl = fcntl(fd, F_GETFL, 0);
if(fl < 0){
perror("ERROR: fcntl():");
return -1;
}
fcntl(fd, F_SETFL, fl & ~(O_NONBLOCK | O_APPEND | O_DSYNC | O_RSYNC | O_SYNC));
tcgetattr(fd, &fo);
fo.c_cc[VMIN] = 1;
fo.c_cc[VTIME] = 0;
tcsetattr(fd, TCSANOW, &fo);
fputs("─────────────────────────────────────────────────── terminal settings\n", stdout);
printf("VMIN = %d\n", fo.c_cc[VMIN]);
printf("VTIME = %d\n", fo.c_cc[VTIME]);
putchar('\n');
return(fd);
之后我的程序进入一个无限的 while 循环,其中 read()
阻塞,直到我在键盘焦点位于 /dev/pts/1
.[=35= 时输入任何键]
我面临的问题是有时我在 /dev/pts/1
中按下一个键,用这个键注册的字节没有传输到驱动程序缓冲区?!字节只停留在/dev/pts/1
。 ASCII(1 字节)字符和 UTF8(多字节)字节会发生这种情况...
我知道 read()
试图从驱动程序缓冲区中读取 请求的 字节数 (BS
)。但如果驱动程序缓冲区中没有 BS
字节可用,它会读取较少的字节。所以......如果一些字节稍后到达,它可以稍后读取它们。但是由于某种原因这些字节永远不会到达驱动程序缓冲区...
什么可能导致字节未到达驱动程序缓冲区并永远保留在 /dev/pts/1
中?
pts
是在虚拟终端连接到系统时创建的(通常是 ssh
)。 pts
连接为 stdin
/stdout
用于连接启动的 shell,因此您已经有一个进程附加到 pts
和读取来自它。
一旦你附加了你的应用程序,你就有效地开始了两个进程(你的应用程序和 shell)之间的竞争,所以谁更快谁就会收到缓冲区的内容。该字符并未保留在 pts
的缓冲区中,而是被附加到 pts
的 shell 读取。
为了能够不中断附加进程的读取,您需要通过通知主多路复用器 ptmx
来拦截 pts
的缓冲区,请参阅 ptmx(4). You can study how it's done in the interceptty[ 了解更多信息=21=]