C Linux串行读取抛出错误

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

我正在尝试使用以下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 = 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,这不是因为它前面有一个连字符)。eoleol2都未定义(这是默认值)

因此,对于您的设置,行尾定义为换行符或回车符(或行首的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);
        }