C Linux串行读取抛出错误
我正在尝试使用以下C代码从串行端口读取数据。我可以成功地写入一台正在侦听的计算机(耶!),但是读取会抛出错误(代码11-资源暂时不可用)。我还注意到我的消息/dmesg日志没有任何关于故障等的信息,所以这很好C Linux串行读取抛出错误,c,linux,serial-port,C,Linux,Serial Port,我正在尝试使用以下C代码从串行端口读取数据。我可以成功地写入一台正在侦听的计算机(耶!),但是读取会抛出错误(代码11-资源暂时不可用)。我还注意到我的消息/dmesg日志没有任何关于故障等的信息,所以这很好 //A bunch of INCLUDES exist here....the the code int fd=0; int status=0; int running=1; char buffer[100]; char message[7]; void main(){ fd
//A bunch of INCLUDES exist here....the the code
int fd=0;
int status=0;
int running=1;
char buffer[100];
char message[7];
void main(){
fd = 1;
fd=open("/dev/ttyM0",O_RDWR | O_NOCTTY);
if(fd == -1)
{
perror("open_port: Unable to open /dev/ttys0");
}
else
{
while(running<20)
{
sprintf(message,"Test%d\r",running);
status=write(fd,message,6);
if(status<0)
{
printf("Error Writing. Status=%d\n %s\n",errno, strerror(errno));
}
status=read(fd,buffer,8); //This throws an error(11). My connected device is writing "Testing/r"
if(status<0)
{
printf("Error Reading. Status=%d \n%s\n",errno, strerror(errno));
//close(fd);
running=running+1;
}
else
{
printf("%s\n\r",buffer);
}
sleep(2);
}
close(fd);
}
} //END MAIN
//此处存在大量包含项……代码
int-fd=0;
int status=0;
int运行=1;
字符缓冲区[100];
字符消息[7];
void main(){
fd=1;
fd=打开(“/dev/ttyM0”,O|RDWR | O|NOCTTY);
如果(fd==-1)
{
perror(“打开_端口:无法打开/dev/ttys0”);
}
其他的
{
(运行时,此处出现缓冲区溢出:
sprintf(message,"Test%d\r",running);
由于消息
声明为:
char message[6];
消息
如果要容纳6个字符的字符串,则其大小必须至少为7个字符,因为需要一个'\0'
终止符
可能还有其他问题,但你应该解决这个问题,看看它是否有什么不同。你在打开
调用中使用了O\u NDELAY
选项。这会使文件描述符无阻塞。这意味着如果你执行了读取
而没有可用数据,那么读取
调用将返回EAGAIN
,这是您看到的错误
目前,您可以从open
中删除O\u NDELAY
。将来,您可能应该再次将其设置为非阻塞状态,并使用select
或poll
来确定何时可以阅读
随着O_NDELAY的消失,程序只是坐在那里等待输入
看起来termios是为规范输入设置的(基于stty输出中的icanon)。在规范(又称熟食)模式下,从串行端口接收的字符在使用read()提供给用户程序之前先进行处理
根据Linux手册页:
在规范模式下:
- 一行一行的输入是可用的
键入其中一个行分隔符时(NL、EOL、EOL2;或EOF at
行的开头)。除EOF外,行分隔符
包含在读取(2)返回的缓冲区中
您的termios还设置了icrnl,这意味着回车符在输入时转换为换行符(除非设置了igncr,这不是因为它前面有一个连字符)。eol和eol2都未定义(这是默认值)
因此,对于您的设置,行尾定义为换行符或回车符(或行首的cntl-D)。请验证远程设备是否实际发送CR或LF控制字符以终止该行。代码中的注释表明它不是(即“/r”不是回车符)
要正确地将read()返回的文本用作字符串,请将请求设置为小于分配的缓冲区大小的一个(以确保追加空终止符的空间)。然后在正确返回后,使用返回的字节计数作为索引来存储字符串终止符
status = read(fd, buffer, sizeof(buffer) - 1);
if (status < 0) {
/* handle error condition */
} else {
buffer[status] = '\0';
printf("%s\n\r", buffer);
}
status=read(fd,buffer,sizeof(buffer)-1);
如果(状态<0){
/*处理错误条件*/
}否则{
缓冲区[状态]='\0';
printf(“%s\n\r”,缓冲区);
}
好消息。我已将此消息更新为char消息[7]然后再次运行软件。我的读取仍然抛出相同的错误。感谢代码审阅!可能相关:是的,我以前读过这篇文章,我同意在使用O_NDELAY标志时数据不会总是可用的,但我通过运行代码循环来处理这一问题。您所指的示例只调用读取一次。@Craig——读取ma第n页用于打开():O_NDELAY与O_NONBLOCK相同。因此,您已经为非阻塞I/O打开了串行端口。您必须预测并正确处理EAGAIN返回代码。如果您不知道如何处理EAGAIN,那么简单的解决方案是执行阻塞I/O。依我看,如果您要做的只是循环等待数据读取,那么您应该使用blocked read.read()不存储以null结尾的文本字符串(除非这是实际传输和接收的文本字符串),因此后续的printf()可能会输出虚假字符。看起来termios是为规范输入设置的(基于stty输出中的icanon)。验证远程设备是否实际发送CR或LF控制字符以终止该行。代码中的注释表明它不是(即“/r”不是回车符)@BenVoigt-如果不使用轮询
或选择
,您将不得不在两次尝试之间休眠,或者使用硬循环来重试读取。这会起作用,但远远不够理想。
status = read(fd, buffer, sizeof(buffer) - 1);
if (status < 0) {
/* handle error condition */
} else {
buffer[status] = '\0';
printf("%s\n\r", buffer);
}