如何使用管道进行非阻塞 IPC(UART 仿真)
问题:
我想编写一些模拟串行端口连接的测试/模拟代码。这 真实的代码如下所示:
DUT <- UART ->测试工具.exe
我的计划是在 Linux 上创建一个测试应用程序 (CodeUnderTest.out),该应用程序分叉以两个(读和写)命名管道作为参数来启动 testtool.out。但我不知道如何使所有管道 IO 非阻塞!
设置看起来像这样:
CodeUnderTest.out <- 命名管道 -> testTool.out(从 CodeUnderTest.out 启动)
我尝试按如下方式打开管道:
open(wpipe,O_WRONLY|O_NONBLOCK);
open(rpipe,O_RDONLY|O_NONBLOCK);
但是写入会阻塞,直到读取器打开 wpipe。接下来我尝试了以下操作:
open(wpipe,O_RDWR|O_NONBLOCK);
open(rpipe,O_RDONLY|O_NONBLOCK);
但是第一条消息的阅读器永远不会获取任何数据(尽管不会阻塞)
我还尝试在每条消息周围添加打开和关闭调用,但这也不起作用...
测试代码:
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
pid_t pid;
char* rpipe, *wpipe,*x;
FILE *rh,*wh;
int rfd,wfd;
void openrpipe( void )
{
rfd = open(rpipe,O_RDONLY|O_NONBLOCK);
rh = fdopen(rfd,"rb");
printf("%sopeningr %x\n",x,rh);
}
void openwpipe( void )
{
//Fails when reader not already opened
//wfd = open(wpipe,O_WRONLY|O_NONBLOCK);
wfd = open(wpipe,O_RDWR|O_NONBLOCK);
wh = fdopen(wfd,"wb");
printf("%sopeningw %x\n",x,wh);
}
void closerpipe( void )
{
int i;
i = fclose(rh);
printf("%sclosingr %d\n",x,i);
}
void closewpipe( void )
{
int i;
i = fclose(wh);
printf("%sclosingw %d\n",x,i);
}
void readpipe( char* expect, int len)
{
char buf[1024];
int i=0;
printf("%sreading\n",x);
while(i==0)
{
//printf(".");
i = fread(buf,1,len,rh);
}
printf("%sread (%d) %s\n",x,i,buf);
}
void writepipe( char* data, int len)
{
int i,j;
printf("%swriting\n",x);
i = fwrite(data,1,len,rh);
j = fflush(rh); //No help!
printf("%sflush %d\n",x,j);
printf("%swrite (%d) %s\n",x,i,data);
}
int main(int argc, char **argv)
{
rpipe = "readfifo";
wpipe = "writefifo";
x = "";
pid = fork();
if( pid == 0)
{
wpipe = "readfifo";
rpipe = "writefifo";
x = " ";
openrpipe();
openwpipe();
writepipe("paul",4);
readpipe("was",3);
writepipe("here",4);
closerpipe();
closewpipe();
exit(0);
}
openrpipe();
openwpipe();
readpipe("paul",4);
writepipe("was",3);
readpipe("here",4);
closerpipe();
closewpipe();
return( -1 );
}
顺便说一句:
要使用上面的测试代码,您需要在当前目录中创建 2 个管道:
mkfifo ./readfifo
mkfifo ./writefifo
更新:
好的,我想我现在有正确的设置。请告诉我是否可以做得更好
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
pid_t pid;
char* rpipe, *wpipe,*x;
int rfd,wfd;
FILE* openpipe( char* str, char* access )
{
FILE* fh;
rfd = open(str,O_RDWR|O_NONBLOCK);
fh = fdopen(rfd,access);
printf("%sopen(%s,%s)=%x\n",x,str,access,fh);
return(fh);
}
void closepipe( FILE* fh )
{
int i;
i = fclose(fh);
printf("%sclosing %d\n",x,i);
}
void readpipe( char* expect, int len, FILE* fh)
{
char buf[1024];
int i=0;
printf("%sreading\n",x);
while(i==0)
{
//printf("%c",strlen(x)?'.':'#');
i = fread(buf,1,len,fh);
}
buf[i] = 0;
printf("%sread (%d) %s\n",x,i,buf);
}
void writepipe( char* data, int len, FILE* fh)
{
int i=0,j;
printf("%swriting\n",x);
//while(i==0)
i = fwrite(data,1,len,fh);
j=fflush(fh);
printf("%sflush %d\n",x,j);
printf("%swrite (%d) %s\n",x,i,data);
}
int main(int argc, char **argv)
{
FILE *rh,*wh;
rpipe = "readfifo";
wpipe = "writefifo";
x = "";
pid = fork();
if( pid == 0)
{
FILE *rh,*wh;
wpipe = "readfifo";
rpipe = "writefifo";
x = " ";
rh=openpipe(rpipe,"rb");
wh=openpipe(wpipe,"wb");
writepipe("paul",4,wh);
readpipe("was",3,rh);
writepipe("here",4,wh);
closepipe(rh);
closepipe(wh);
exit(0);
}
rh=openpipe(rpipe,"rb");
wh=openpipe(wpipe,"wb");
readpipe("paul",4,rh);
writepipe("was",3,wh);
readpipe("here",4,rh);
closepipe(rh);
closepipe(wh);
return( -1 );
}
Problem:
I would like to write some test/emulation code that emulates a serial port connection. The
real code looks like this:
DUT <- UART -> testtool.exe
My plan is to use create a test application (CodeUnderTest.out) on linux that forks to launch testool.out with two (read & write) named pipes as arguments. But I cannot figure out how to make all the pipe IO non-blocking!
The setup would look like this:.
CodeUnderTest.out <- named pipes -> testTool.out (lauched from CodeUnderTest.out)
I have tried opening the pipes as following:
open(wpipe,O_WRONLY|O_NONBLOCK);
open(rpipe,O_RDONLY|O_NONBLOCK);
But the write blocks until the reader opens the wpipe. Next I tried the following:
open(wpipe,O_RDWR|O_NONBLOCK);
open(rpipe,O_RDONLY|O_NONBLOCK);
But then the reader of the first message never gets any data (doesn't block though)
I also tried adding open and close calls around each message, but that didn't work either...
Test code:
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
pid_t pid;
char* rpipe, *wpipe,*x;
FILE *rh,*wh;
int rfd,wfd;
void openrpipe( void )
{
rfd = open(rpipe,O_RDONLY|O_NONBLOCK);
rh = fdopen(rfd,"rb");
printf("%sopeningr %x\n",x,rh);
}
void openwpipe( void )
{
//Fails when reader not already opened
//wfd = open(wpipe,O_WRONLY|O_NONBLOCK);
wfd = open(wpipe,O_RDWR|O_NONBLOCK);
wh = fdopen(wfd,"wb");
printf("%sopeningw %x\n",x,wh);
}
void closerpipe( void )
{
int i;
i = fclose(rh);
printf("%sclosingr %d\n",x,i);
}
void closewpipe( void )
{
int i;
i = fclose(wh);
printf("%sclosingw %d\n",x,i);
}
void readpipe( char* expect, int len)
{
char buf[1024];
int i=0;
printf("%sreading\n",x);
while(i==0)
{
//printf(".");
i = fread(buf,1,len,rh);
}
printf("%sread (%d) %s\n",x,i,buf);
}
void writepipe( char* data, int len)
{
int i,j;
printf("%swriting\n",x);
i = fwrite(data,1,len,rh);
j = fflush(rh); //No help!
printf("%sflush %d\n",x,j);
printf("%swrite (%d) %s\n",x,i,data);
}
int main(int argc, char **argv)
{
rpipe = "readfifo";
wpipe = "writefifo";
x = "";
pid = fork();
if( pid == 0)
{
wpipe = "readfifo";
rpipe = "writefifo";
x = " ";
openrpipe();
openwpipe();
writepipe("paul",4);
readpipe("was",3);
writepipe("here",4);
closerpipe();
closewpipe();
exit(0);
}
openrpipe();
openwpipe();
readpipe("paul",4);
writepipe("was",3);
readpipe("here",4);
closerpipe();
closewpipe();
return( -1 );
}
BTW:
To use the testcode above you need will need to create 2 pipes in the current dir:
mkfifo ./readfifo
mkfifo ./writefifo
UPDATE:
Okay I think I have the right settings now. Please let me know if it can be done better
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
pid_t pid;
char* rpipe, *wpipe,*x;
int rfd,wfd;
FILE* openpipe( char* str, char* access )
{
FILE* fh;
rfd = open(str,O_RDWR|O_NONBLOCK);
fh = fdopen(rfd,access);
printf("%sopen(%s,%s)=%x\n",x,str,access,fh);
return(fh);
}
void closepipe( FILE* fh )
{
int i;
i = fclose(fh);
printf("%sclosing %d\n",x,i);
}
void readpipe( char* expect, int len, FILE* fh)
{
char buf[1024];
int i=0;
printf("%sreading\n",x);
while(i==0)
{
//printf("%c",strlen(x)?'.':'#');
i = fread(buf,1,len,fh);
}
buf[i] = 0;
printf("%sread (%d) %s\n",x,i,buf);
}
void writepipe( char* data, int len, FILE* fh)
{
int i=0,j;
printf("%swriting\n",x);
//while(i==0)
i = fwrite(data,1,len,fh);
j=fflush(fh);
printf("%sflush %d\n",x,j);
printf("%swrite (%d) %s\n",x,i,data);
}
int main(int argc, char **argv)
{
FILE *rh,*wh;
rpipe = "readfifo";
wpipe = "writefifo";
x = "";
pid = fork();
if( pid == 0)
{
FILE *rh,*wh;
wpipe = "readfifo";
rpipe = "writefifo";
x = " ";
rh=openpipe(rpipe,"rb");
wh=openpipe(wpipe,"wb");
writepipe("paul",4,wh);
readpipe("was",3,rh);
writepipe("here",4,wh);
closepipe(rh);
closepipe(wh);
exit(0);
}
rh=openpipe(rpipe,"rb");
wh=openpipe(wpipe,"wb");
readpipe("paul",4,rh);
writepipe("was",3,wh);
readpipe("here",4,rh);
closepipe(rh);
closepipe(wh);
return( -1 );
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
一般来说,模拟串行端口进行此类测试的最佳方法是使用伪终端,因为串行端口是
tty
,因此是pty
。posix_openpt()
、grantpt()
、unlockpt()
和ptsname()
是您需要的调用。 Master端通过设备模拟器进行读写,Slave端作为串口打开给被测试的程序。In general, the best way to emulate a serial port for this kind of testing is to use a pseudo-terminal, since a serial port is a
tty
and so is apty
.posix_openpt()
,grantpt()
,unlockpt()
andptsname()
are the calls you will need. The master side is read and written by the device emulator, and the slave side is passed as the serial port to open to the program being tested.在有读取器之前不要写入管道。您应该能够使用
select
或poll
来确定阅读器何时连接。Don't write to the pipe until there's a reader. You should be able to use
select
orpoll
to find out when a reader connects.