C write()在调用close(fd)之前不发送数据

时间:2010-07-12 12:55:04

标签: c linux serial-port tty

所以我有这个测试代码通过USB串口发送“HELLO”:

int fd;
struct termios tty;

if((fd = open("/dev/ttyUSB0", O_WRONLY|O_NONBLOCK|O_NOCTTY)) == -1){
err(1, "Cannot open write on /dev/ttyUSB0");
}

tcgetattr(fd, &tty);
tty.c_iflag = 0;
tty.c_oflag = 0;
tty.c_lflag = 0;
tty.c_cflag = 0;
tty.c_cc[VMIN] = 0;
tty.c_cc[VTIME] = 0;
cfsetospeed(&tty, B19200);
cfsetispeed(&tty, B19200);
tty.c_cflag |= CREAD|CRTSCTS|HUPCL|CS8;
tcsetattr(fd, TCSANOW, &tty);

printf("Write: %i\n", write(fd, "HELLO", 5));

sleep(5);

if(close(fd) != 0){
warn("Could not close write fd");
}

程序执行正常并发送“HELLO”但有一个问题。调用write()函数时似乎没有发送“HELLO”,而是在文件描述符关闭时发送。我添加了上面的sleep(5)行来测试这个理论,果然,“HELLO”在程序执行后约5秒发送。如何在write()命令之后立即发送“HELLO”而不是close()?

8 个答案:

答案 0 :(得分:8)

该设备是一个tty设备,所以fsync不会有帮助,也许不会fflush。

默认情况下,设备在规范模式下工作,这意味着数据被打包成行单位。您可能会发现在数据中添加cr / lf对将导致它被发送。

您需要确保规范模式已关闭。此外,R的答案将是有用的。

http://en.wikibooks.org/wiki/Serial_Programming/termios

答案 1 :(得分:5)

来自write()的手册页:

  

从write()成功返回并不能保证数据已提交到磁盘。事实上,在一些错误的实现上,它甚至不能保证已成功为数据保留空间。唯一可以确定的方法是在写完所有数据后调用fsync(2)。

您需要在文件描述符上调用fsync()以确保实际提交数据。

答案 2 :(得分:3)

首先,不知道为什么你首先将所有termios字段设置为0,然后在没有对其前面的0进行任何修改的情况下,决定在cflag上设置通常的rs232标志。 (而不是在没有OR的情况下直接执行此操作,现在将其设置为0,以上)。

您可能想要的 - 而不是设置所有这些标志只是cfmakeraw()的termios字段。

另外,sync();没有任何参数(NOT fsync!;)似乎将所有挂起的输出发送到所有文件描述符,而不仅仅是块设备。还有tcp套接字和rs232 ..

并且open()有一个选项O_SYNC(O_SYNC和O_ASYNC具有令人困惑的名称,但与被驱动的串行线路协议无关,一个立即提交write(),另一个生成一个信号当输入变得可用时捕获(有点像dos上基于irq的rs232;)

在open()中设置O_SYNC可能已经解决了您的问题。

也'通过读取另一端的数据'......有些东西叫做'leds'和'resistor',你可以连接到TXD并查看数据;)还有一些叫做'rs232 breakout'的东西box'或可以使其直接可见的范围 - ;)比“猜测”哪一方行为不正确更容易。

警告:没有测试代码。它汇编。但是我把所有的ttyUSB0电缆放在另一栋楼里。但我认为你的主要问题是O_SYNC。将所有termios crap设置为0与cfmakeraw()几乎相同...也为什么设置CREAD如果你要打开它只写? (为什么打开它只写而不是写入? - 而且只有写入你不必害怕它成为一个控制tty(O_NOCTTY;)所以在只写的情况下,这也不是完全需要..

刚注意到%i(同样适用于%d btw)格式化程序也触发了类型不匹配警告,写入()的ssize_t返回值,以便将其转换为(int)

#include<termios.h>
#include<stdio.h>
#include<unistd.h>
#include<fcntl.h>

void main(){
int fd;
struct termios tty;
fd=-1;
while(fd<0){fd=open("/dev/ttyUSB0",O_WRONLY|O_NONBLOCK|O_NOCTTY|O_SYNC);sleep(1);};
cfmakeraw(&tty);
tty.c_cflag=CREAD|CRTSCTS|HUPCL|CS8;
cfsetospeed(&tty,B19200);
cfsetispeed(&tty,B19200);
tcsetattr(fd,TCSANOW,&tty);
printf("Write: %i\n",(int)write(fd,"HELLO",5));
sync();//if all else fails, also try without, O_SYNC should already fix that.
close(fd);
};

答案 3 :(得分:2)

输出端口通常是缓冲的,因此在写入输出流与实际发送到磁盘,线路或其他内容之间存在更大或更小的差距。这通常是为了提高效率。

请参阅fflush(3)以强制将缓冲区提交到输出。

你也可以以一种非缓冲的方式打开输出描述符,但使用fflush来表示“就是这样,我已经完成了”,可能更好。

答案 4 :(得分:0)

更改此行:

tty.c_cc[VMIN] = 0;

到此:

tty.c_cc[VMIN] = 1;

答案 5 :(得分:-1)

缓冲区未刷新。 fflush。

答案 6 :(得分:-1)

请参阅this question。因此,您需要刷新文件,以便在需要时进行IO。

答案 7 :(得分:-1)

尝试做

fflush( NULL );
write()之后

。也许有一些内部缓冲区没有刷新。