代码之家  ›  专栏  ›  技术社区  ›  Gordon

在Linux中读取和写入同一文件描述符时出现问题

  •  0
  • Gordon  · 技术社区  · 8 年前

    我在Linux中成功读取了fd,但读取了0字节,这意味着已经达到EOF。我应该在每次读取中读取19个字节。

    该项目是一个电机驱动程序,它发送19个字节的数据包来驱动2个直流电机,还需要读取来自电机的相同大小的数据包,以及更新的位置、命令和状态信息。

    我这样打开fd:

    mc_fd = InitPort("/dev/ttyS1", "COM2", O_NONBLOCK | O_RDWR | O_SYNC, B115200); 
    

    以下是初始化端口的函数:

    int InitPort( char *port, char *name, int oflags, speed_t baudRate ) {
    
    int fd;                             // File descriptor
    fd = open(port, oflags);            // Open the port like a file
    assert(fd > 0);                     // Open returns -1 on error
    
    struct termios options;             // Initialize a termios struct
    tcgetattr(fd, &options);            // Populate with current attributes
    cfsetospeed (&options, baudRate);   // Set baud rate out
    cfsetispeed (&options, baudRate);   // Set baud rate in (same as baud rate out)
    options.c_cflag &= ~CSIZE;          // Clear bit-length flag so it can be set
        //8N1 Serial Mode
        options.c_cflag |=  CS8;        // Set bit-length:  8
        options.c_cflag &= ~PARENB;     // Set parity:      none
        options.c_cflag &= ~CSTOPB;     // Set stop bit:        1
        options.c_cflag &= ~CRTSCTS;    // Set flow control:    none
    
    options.c_iflag &= ~ICANON;         // Enable canonical input
    options.c_oflag &= ~OPOST;          // Disables all output processing (prevents CR in output)
    options.c_cflag |= (CLOCAL | CREAD);// Enable receiver, and set local mode
    tcsetattr(fd, TCSANOW, &options);   // Set new attributes to hardware
    return fd;
    }
    

    最初,我只使用O\U RDWR标志,fd的读取将因EAGAIN(或EWoldblock)而失败。我一直在尝试同步和非阻塞设置,以查看是否可以接收数据包。至少现在我读得很成功(我想)。

    我能够以120Hz的频率写出数据包,并且fd的读取以相同的速率返回“成功”,尽管读取了0字节。

    如何获取read()来读取传入的数据包? 以下是读取的代码以及终端的输出:

    bytesRead = read( mc_fd, readPacket, MC_PACKET_SIZE );
    printf("\npacket: %019X\n", &readPacket);
    perror("error type ");
    printf("bytes read = %d\n", bytesRead);
    
    packet: 00000000000B63B4140
    error type : Success
    bytes read = 0
    

    数据包最低有效部分中的8位十六进制数始终与所示的数字相似,并且不是数据包中预期的数字。

    这是在嵌入式linux SBC(单板计算机)上运行的Debian。我能够毫无问题地读取程序中的其他文件描述符。我对Linux还是相当陌生,可能遗漏了一些明显的东西。谢谢

    2 回复  |  直到 8 年前
        1
  •  4
  •   sawdust    8 年前

    ...但读取0字节意味着已达到EOF。

    不准确的
    你在看连续剧 航空站 在里面 非阻塞 模式
    返回码为零意味着当时终端没有可用的数据。
    这就是您的程序(您应该发布)在使用非阻塞模式时必须处理的内容。

    如何获取read()来读取传入的数据包?

    使用阻塞模式(即从 打开() )如果不希望看到返回代码为零(或 errno 设置为EAGAIN)。
    但不要期望 读取() 除非您的文本处于规范模式,否则系统调用会为您对齐数据包。

    学习 this answer .

    数据包最低有效部分中的8位十六进制数始终与所示的数字相似,并且不是数据包中预期的数字。

    您发布的代码太少(这是结束问题的理由),但您试图将数据读入 readPacket ,似乎是(字节?)大堆
    但之后你请 读取数据包 就好像它是 printf() .

    打印数组地址的地址(或整数变量的地址)不会产生任何效果(例如。 “8位十六进制数…始终与所示类似” ). 您尚未显示可能收到的任何内容。

    如果您使用的是一个小的32位endian处理器,那么将字节数组作为一个长整数进行访问将颠倒每个字的字节顺序(即。 “不是预期的” ),只访问前四个字节,这可以由八个十六进制数字表示。

    我对Linux还是相当陌生,广告可能遗漏了一些明显的东西。

    虽然Linux是(几乎)“一切都是文件”的操作系统之一,但这些“文件”可能并不相等。尤其是程序访问的设备文件,即。 /dev/ttyS1 ,是一个串行终端设备。串行终端需要额外的设备配置,这是通过 termios公司 结构
    因为你只发布了几行程序,没有提到任何 termios公司 除了波特率之外,您的程序无法评估。


    补遗

    现在您已经发布了一些初始化代码,显然还有一些错误。

    不管您的编程经验如何,以下代码与注释之间的不一致是一个可能延长调试时间的缺陷。

    options.c_iflag &= ~ICANON;         // Enable canonical input
    

    清除ICANON标志将启用非规范输入,与注释所述相反。
    您尚未描述19字节的数据,因此无法确定规范模式是否合适。

    termios初始化编写得很好(即使用正确的布尔运算符而不是直接赋值),但不完整(基于为非规范模式执行的现有代码)。
    只需使用 cfmakeraw() 常规
    您的代码不会初始化VMIN和VTIME参数,但由于非规范和非阻塞模式的组合禁用了该功能,所以这并不重要。

    由于您在描述您试图做的事情方面做得很差,因此无法建议进行适当的更正。

        2
  •  -1
  •   Turbo J    8 年前

    我应该在每次读取中读取19个字节。[...]

    “/开发/ttyS1”

    在只有16字节fifo或更少的串行端口上?我认为那行不通。

    串行端口是字符设备,这有一个很好的理由——您希望以一种方式进行编码,从零字节(如果启用超时)、一字节到内部fifo的大小。即使你(试图)那样发送,也不要期望它们保持整齐。

    推荐文章