Chinaunix

标题: 各位,有了新的问题,再次麻烦大家give me a hand [打印本页]

作者: NewCore    时间: 2007-06-04 17:42
标题: 各位,有了新的问题,再次麻烦大家give me a hand
这里是http://linux.chinaunix.net/bbs/thread-899878-1-1.html的续贴,现在遇到了新的问题

问题如下: 我首先把stdout重定向到了一个文件a.out, 然后一个子进程执行system("tar > stdout"),把数据写到文件a.out中,同时,主进程read文件a.out,把命令执行结果读出来,现在我发现system命令执行时把输出先缓存起来了,所以导致我在主进程中不能及时读到数据,而只有等到system命令执行完了,系统才把数据从缓存中写到文件a.out.

请问用什么办法,使system即使把输出写到文件a.out,而不是得等到它执行完|???

如果有人说为什么用这个办法,而不用...,请参考帖子http://linux.chinaunix.net/bbs/thread-899878-1-1.html,

我也是没有办法之举!!!现在只求解决问题.
作者: MMMIX    时间: 2007-06-04 18:14
原帖由 NewCore 于 2007-6-4 17:42 发表于 1楼  
这里是http://linux.chinaunix.net/bbs/thread-899878-1-1.html的续贴,现在遇到了新的问题

问题如下: 我首先把stdout重定向到了一个文件a.out, 然后一个子进程执行system("tar > stdout"),把数 ...

我一直很好奇你为什么不用 fork+exec 而坚持要用 system ?用 fork+exec 的话许多东西都是你可以控制的,但用 system 则否。
作者: NewCore    时间: 2007-06-04 18:24
to MMMIX

谢谢回复!

嗯,我记得在第一个帖子里,你就让我用exec代替system,我也是这样尝试了,但是没有解决问题啊!

我现在也可以用exec代替system,只是我想请问一下,是否用exec就可以把输出重定向到文件,且是及时把结果写到文件,而不是等到命令结束返回?

其实,我还用pthread + system的方式尝试过,主线程create子线程而不是子进程(我怀疑过是fork + system的问题),但是问题还是一样,system就是不及时写文件,而是等到命令返回才写文件。

我已经快黔驴技穷了,找到了问题所在,却不知道该如何解决。。。希望能给我一些好办法和思路。
作者: NewCore    时间: 2007-06-04 18:27
我先回家了,我会及时关注各位的回复,谢谢!
作者: MMMIX    时间: 2007-06-04 19:03
原帖由 NewCore 于 2007-6-4 18:24 发表于 3楼  
to MMMIX

谢谢回复!

嗯,我记得在第一个帖子里,你就让我用exec代替system,我也是这样尝试了,但是没有解决问题啊!

我现在也可以用exec代替system,只是我想请问一下,是否用exec就可以把输出重定向到文件,且是及时把结果写到文件,而不是等到命令结束返回?

当然可以,适当的设置缓冲模式就行了。甚至你还可以在打开文件的时候指定同步标志,或者在写完文件的时候手工刷新。
作者: anhongkui    时间: 2007-06-04 19:34
设置缓冲模式
行缓冲或者无缓冲
作者: NewCore    时间: 2007-06-04 21:48
原帖由 MMMIX 于 2007-6-4 19:03 发表于 5楼  

当然可以,适当的设置缓冲模式就行了。甚至你还可以在打开文件的时候指定同步标志,或者在写完文件的时候手工刷新。



大哥,你又给了我一线希望,请问你说得“适当设置缓冲模式”能不能具体点?

“甚至你还可以在打开文件的时候指定同步标志,或者在写完文件的时候手工刷新。”能不能具体点,同时我也在网上查一下。

现在在家了,没环境,明天到公司我再试看,请继续跟踪,谢谢!
作者: NewCore    时间: 2007-06-04 21:49
原帖由 anhongkui 于 2007-6-4 19:34 发表于 6楼  
设置缓冲模式
行缓冲或者无缓冲


谢谢,我查下资料,如果不麻烦的话,能不能再详细点?
作者: MMMIX    时间: 2007-06-04 22:03
原帖由 NewCore 于 2007-6-4 21:48 发表于 7楼  



大哥,你又给了我一线希望,请问你说得“适当设置缓冲模式”能不能具体点?

“甚至你还可以在打开文件的时候指定同步标志,或者在写完文件的时候手工刷新。”能不能具体点,同时我也在网上查一下。

...

强烈建议 APUE2。
作者: NewCore    时间: 2007-06-04 22:51
为了便于解决问题,我在这里还是把关键代码列一下,代码在公司,我只能大概给出个思路了:

void * bk_thread(void *)
{
    int fd;
   
    fd = open("a.out", O_CREAT | O_RDWR);   /* a.out 作为保存输出信息的文件 */
   
    dup2(fd, 1)

    if(0 == fork())
    {
        system("tar ... >&1");        /* 故意加 >&1 到输出,实际上到a.out文件 */
        exit(1);
    }
   
    int fd_dup;
    int count;

    fd_dup = dup(fd);    /* 后面用fd_dup来操作 */

    while((count = read()) >= 0)         /* 这里count一直=0,除非system()返回,那个时候数据才被写道文件a.out中 */
    {
        if(count == 0)                /* 数据为0,判断子进城是否结束,结束就退出,没结束sleep一下后继续去读 */
        {
            
        }
        else                        /* 处理读出来的数据 */
        {
        }      
    }   
}

int main()
{

    pthread_t tid;

    /* do something */

    pthread_create(bk_thread);
    pthread_join(&tid, NULL);
}

我大概思路就是这样了,我初步定为应该是缓冲的问题,请看看是吗?

to MMMIX, 我查下有问题在问吧。上面应该是这个问题导致的吗?
作者: NewCore    时间: 2007-06-05 09:34
各位,我按照昨天的提示,打开文件时设置同步标志,然后加上了缓冲设置,如下:

void * bk_thread(void *)
{
    int fd;
    FILE * fp;
    char linebuf[BUFLEN + 1];

    fd = open("a.out", O_CREAT | O_RDWR | O_SYNC);   /* a.out 作为保存输出信息的文件, */

/*************设置为行缓冲*******************/   
    fp = fdopen(fd, "w+");
    setvbuf(fp, linebuf, _IOLBF, BUFLEN);
/*****************************************/   
    dup2(fd, 1)

    if(0 == fork())
    {
        system("tar ... >&1");        /* 故意加 >&1 到输出,实际上到a.out文件 */
        exit(1);
    }
   
    int fd_dup;
    int count;

    fd_dup = dup(fd);    /* 后面用fd_dup来操作 */

    while((count = read()) >= 0)         /* 这里count一直=0,除非system()返回,那个时候数据才被写道文件a.out中 */
    {
        if(count == 0)                /* 数据为0,判断子进城是否结束,结束就退出,没结束sleep一下后继续去读 */
        {
            
        }
        else                        /* 处理读出来的数据 */
        {
        }      
    }   
}

现在还是读不出来数据啊?
作者: flw2    时间: 2007-06-05 12:41
实在是叙述的糟糕,能否再清楚的描述一下你

想要怎么样
作者: flw2    时间: 2007-06-05 12:42
所有的缓冲如果不起作用,那么肯定是因为你并没有改变tar,也许tar是有缓冲的。
不知道为什么要这么干。
作者: flw2    时间: 2007-06-05 12:44
搂住,我没有别的意思,我只是希望你能描述的清楚一点。
作者: flw2    时间: 2007-06-05 12:46
我首先把stdout重定向到了一个文件a.out, 然后一个子进程执行system("tar > stdout"),把数据写到文件a.out中,同时,主进程read文件a.out,把命令执行结果读出来

fp = popen("tar ..","r");
tar应该也不至于让你等太久呀。
作者: NewCore    时间: 2007-06-05 13:14
原帖由 flw2 于 2007-6-5 12:44 发表于 14楼  
搂住,我没有别的意思,我只是希望你能描述的清楚一点。


好,我再详细说说。我要解开一个tar包,同时把tar命令执行的输出(即知道解包后的文件名列表)截取下来,现在我用的办法是首先把标准输出重定向到文件a.out,然后一个子进程system("tar")到标准输出,实际上是到了a.out,然后主进程在从文件a.out中读出文件列表,即tar命令的输出。

本来应该是很简单的一个事情,但是现在问题在于:子进程在执行system的时候,不时如同我们平时在shell下执行tar时那样,一边解包,一边把输出到文件,而是把书出缓存起来(我估计是这样) ,直到tar执行完了,才把输出一起写到文件a.out中,但是,这是不满足我的需求的.我需要及时知道当前解包到那个文件了,说白了,我需要对当前正在解包的文件的名字作其他处理.

上面就是这个的代码实现,而我现在就是不知道如何解决我上面说的问题,我尝试了很多办法,都没有效果,希望你能给我点提示?谢谢!
作者: NewCore    时间: 2007-06-05 13:16
原帖由 flw2 于 2007-6-5 12:46 发表于 15楼  
我首先把stdout重定向到了一个文件a.out, 然后一个子进程执行system("tar > stdout"),把数据写到文件a.out中,同时,主进程read文件a.out,把命令执行结果读出来

fp = popen("tar ..",& ...


我们的系统是经过裁减的嵌入式系统,popen已经被裁掉了,我有苦难言!
作者: NewCore    时间: 2007-06-05 13:37
原帖由 flw2 于 2007-6-5 12:42 发表于 13楼  
所有的缓冲如果不起作用,那么肯定是因为你并没有改变tar,也许tar是有缓冲的。
不知道为什么要这么干。


奇怪的是,如果tar命令自己有缓冲,在shell里直接执行tar命令的时候,也不是说解包完了,才在屏幕上显示出来,而是一边解包,一边执行的.
作者: NewCore    时间: 2007-06-06 00:37
没人了吗?其实,我也觉得这个问题确实是相当的诡异...

我已作了最坏打算,下了tar的源码,准备把它编到自己的代码里面...铁了心要把它搞定。
作者: langue    时间: 2007-06-06 08:07
这个任务用 shell 写不好吗?
作者: mirnshi    时间: 2007-06-06 09:53
最简单的就是popen,如果有可能,可以自己摘抄一个popen。如果只能选择system,而且>转向不灵的,是不是可以采用|管道,经由另一个你自己编写的程序读取stdin,然后通过unix-socket之类的传给主控程序。文件操作应该是有缓冲的。管道没有。
作者: NewCore    时间: 2007-06-06 10:58
原帖由 langue 于 2007-6-6 08:07 发表于 20楼  
这个任务用 shell 写不好吗?



我不会用shell做UI...
作者: NewCore    时间: 2007-06-06 11:06
原帖由 mirnshi 于 2007-6-6 09:53 发表于 21楼  
最简单的就是popen,如果有可能,可以自己摘抄一个popen。如果只能选择system,而且>转向不灵的,是不是可以采用|管道,经由另一个你自己编写的程序读取stdin,然后通过unix-socket之类的传给主控程序。文件 ...



研究tar代码中,支持自己裁减

我准备把gzip解压裁掉,然后在代码里面自己用gzip解压,保留tar的解包功能,得到解包后的文件名就OK了,还在实验中.

现在比较郁闷的是,这段代码有些extern的函数,先尝试一下再看吧...
作者: MMMIX    时间: 2007-06-06 11:58
原帖由 NewCore 于 2007-6-6 11:06 发表于 23楼  



研究tar代码中,支持自己裁减

我准备把gzip解压裁掉,然后在代码里面自己用gzip解压,保留tar的解包功能,得到解包后的文件名就OK了,还在实验中.

现在比较郁闷的是,这段代码有些extern的函数,先尝试一下 ...

现在是越绕越远了
作者: flw2    时间: 2007-06-06 13:21
tar的输出是什么?我觉得tar就是输出一个目录树。

所以你要什么呢?目录树的结构(名字而不是内容)?
作者: NewCore    时间: 2007-06-06 13:33
原帖由 flw2 于 2007-6-6 13:21 发表于 25楼  
tar的输出是什么?我觉得tar就是输出一个目录树。

所以你要什么呢?目录树的结构(名字而不是内容)?


我要内容. 现在的问题是,我得不到.
作者: NewCore    时间: 2007-06-06 13:39
原帖由 flw2 于 2007-6-6 13:21 发表于 25楼  
tar的输出是什么?我觉得tar就是输出一个目录树。

所以你要什么呢?目录树的结构(名字而不是内容)?


现在以下几种方法,已测试不可行:

1. popen -------------- popen被裁减,运行popen时系统直接报segment fault
2. fork + system(exec) + pipe ------------- 重定向到管道,从管道中读
3. fork + system(exec) + file---------------- 重定向到文件,在从文件中读

现在
4. 把tar源码编进来, 得到tar包中文件------------尝试中
5. ???
作者: flw2    时间: 2007-06-06 14:29
原帖由 NewCore 于 2007-6-6 13:33 发表于 26楼  


我要内容. 现在的问题是,我得不到.


你要什么内容,我怎么给你?
假设tar已经完成了,你会取吗?tar又不是一个文件
作者: flw2    时间: 2007-06-06 14:31
tar会mkdir,你想得到dir名称还是什么?

可能是因为不了解tar,我真还不明白你要什么,我试图努力看懂你说的,但是还是不明白。

你可以写个函数声明,我可以看看我会不会实现这个函数。
作者: NewCore    时间: 2007-06-06 14:48
原帖由 flw2 于 2007-6-6 14:31 发表于 29楼  
tar会mkdir,你想得到dir名称还是什么?

可能是因为不了解tar,我真还不明白你要什么,我试图努力看懂你说的,但是还是不明白。

你可以写个函数声明,我可以看看我会不会实现这个函数。


稍等,我在回复,为了说的详细,花点时间.
作者: NewCore    时间: 2007-06-06 14:57
原帖由 flw2 于 2007-6-6 14:31 发表于 29楼  
tar会mkdir,你想得到dir名称还是什么?

可能是因为不了解tar,我真还不明白你要什么,我试图努力看懂你说的,但是还是不明白。

你可以写个函数声明,我可以看看我会不会实现这个函数。




to flw2:

没有冒犯的意思,没想到我的表述能力如此之差...我一直试图把问题说得明白点,尽管就像我开始说的,这个问题很怪异...

tar确实不是一个文件,但是我这样执行tar -zxvf file.tar,那么tar在执行的时候就会把tar包中的文件名输出到标准输出,如果是屏幕,就看到一行一行的解包出来的文件名.

OK,我要的就是这所有的文件名.这里关键是,我需要在tar命令执行的同时,获得这个文件名,而不是tar执行完.

我用了上面的方法,但是没有用.原因是,tar命令执行完才把包中的文件名输出到标准输出.(假如我们没有重定向,什么都没做).这是不符合我的需求的.

如果你觉得一个接口更能说明问题,那么可以认为就这样的一个接口
int my_tar(char * _tar_filename)
{
}
他做得事就是
1 解包file.tar.gz
2 同时把file.tar.gz包中的文件的名字(文件名字符串)保存到文件a.out中.

至于如何读出来,那不是问题了.现在就是这样的一个简单功能,如果是上面我列出来的方法,那就不用了.

谢谢你的关注,我期待的你的回复
作者: flw2    时间: 2007-06-06 15:12
呵呵,别用这么严重的词,我明白你的意思了,你就是要文件名,但是却不想完之后在出来,确实很奇怪。
你现在的问题是tar的输出并没有在文件出来的同时打印出来对吗?
作者: NewCore    时间: 2007-06-06 15:17
原帖由 flw2 于 2007-6-6 15:12 发表于 32楼  
呵呵,别用这么严重的词,我明白你的意思了,你就是要文件名,但是却不想完之后在出来,确实很奇怪。
你现在的问题是tar的输出并没有在文件出来的同时打印出来对吗?



完全正确
作者: flw2    时间: 2007-06-06 15:22
为什么不能等它完了,而且我跟踪了一下,好像是先打印的呀。


rmdir("misc.o")                         = -1 ENOTDIR (Not a directory)
unlink("misc.o")                        = 0
open("misc.o", O_WRONLY|O_CREAT|O_EXCL|O_LARGEFILE, 0644) = 4
write(4, "\37\213\10\0;\274VF\0\3\355\301\1\r\0\0\0\302\240\367O"..., 45) = 45
作者: flw2    时间: 2007-06-06 15:23
就是说它是先打印名字,然后再生成文件的。
作者: flw2    时间: 2007-06-06 15:25
我知道了,通常tar是行缓冲的,但是当你定向到文件a.out的时候成为全缓冲了。
作者: flw2    时间: 2007-06-06 15:27
定向到管道也没有用。如果你非要立马取结果,那么我现在暂时有两种办法

1.伪终端
2.该tar的代码

1不需要改代码,但是需要稍微折腾一下。
2很简单
作者: flw2    时间: 2007-06-06 15:28
楼主
你的条件,不能等待是很严格吗?要不结束之后再遍历一下多简单
作者: NewCore    时间: 2007-06-06 15:35
原帖由 flw2 于 2007-6-6 15:25 发表于 36楼  
我知道了,通常tar是行缓冲的,但是当你定向到文件a.out的时候成为全缓冲了。



是的! 不只是到a.out,重定向到管道的时候,也没有数据,后来我才发现这其实是一个问题.
作者: NewCore    时间: 2007-06-06 15:36
原帖由 flw2 于 2007-6-6 15:27 发表于 37楼  
定向到管道也没有用。如果你非要立马取结果,那么我现在暂时有两种办法

1.伪终端
2.该tar的代码

1不需要改代码,但是需要稍微折腾一下。
2很简单



现在我也只好用2种办法,还在折腾中.
作者: NewCore    时间: 2007-06-06 15:36
原帖由 flw2 于 2007-6-6 15:28 发表于 38楼  
楼主
你的条件,不能等待是很严格吗?要不结束之后再遍历一下多简单



这样对我的应用来说就没有任何意思,我需要其实就是把文件名拿来显示到自己的UI上.
作者: flw2    时间: 2007-06-06 15:37
很好办,它确实是到输出,直接
main开头,setbuf(stdout,NULL);
作者: NewCore    时间: 2007-06-06 15:39
to flw2:

我现在下载了个busybox上的tar的源代码,现在可以编到我自己的程序里了,但是tar执行的时候出现了错误,还在修改中

看来是没有其他颁发了,后续有问题我在请教吧.或者你有可用的tar得源码? 那就省了我很多事了.
作者: NewCore    时间: 2007-06-06 15:40
原帖由 flw2 于 2007-6-6 15:37 发表于 42楼  
很好办,它确实是到输出,直接
main开头,setbuf(stdout,NULL);



这个我试过了阿,本贴中,我贴出来的代码就做过这样的尝试啊....
作者: NewCore    时间: 2007-06-06 15:41
这个是我发在前面贴子里的:

各位,我按照昨天的提示,打开文件时设置同步标志,然后加上了缓冲设置,如下:

void * bk_thread(void *)
{
    int fd;
    FILE * fp;
    char linebuf[BUFLEN + 1];

    fd = open("a.out", O_CREAT | O_RDWR | O_SYNC);   /* a.out 作为保存输出信息的文件, */

/*************设置为行缓冲*******************/   
    fp = fdopen(fd, "w+");
    setvbuf(fp, linebuf, _IOLBF, BUFLEN);
/*****************************************/   
    dup2(fd, 1)

    if(0 == fork())
    {
        system("tar ... >&1");        /* 故意加 >&1 到输出,实际上到a.out文件 */
        exit(1);
    }
   
    int fd_dup;
    int count;

    fd_dup = dup(fd);    /* 后面用fd_dup来操作 */

    while((count = read()) >= 0)         /* 这里count一直=0,除非system()返回,那个时候数据才被写道文件a.out中 */
    {
        if(count == 0)                /* 数据为0,判断子进城是否结束,结束就退出,没结束sleep一下后继续去读 */
        {
            
        }
        else                        /* 处理读出来的数据 */
        {
        }      
    }   
}

现在还是读不出来数据啊?
作者: flw2    时间: 2007-06-06 15:43
原帖由 NewCore 于 2007-6-6 15:40 发表于 44楼  



这个我试过了阿,本贴中,我贴出来的代码就做过这样的尝试啊....


老大,这个要在tar的main函数中,
作者: flw2    时间: 2007-06-06 15:44
我有源码,这些不都是公开的吗。busybox里的tar也有个main函数呀,你在关键地方检察一下,比如
if (argv[0] == "tar")
setbuf NULL
作者: NewCore    时间: 2007-06-06 15:46
原帖由 flw2 于 2007-6-6 15:43 发表于 46楼  


老大,这个要在tar的main函数中,



恩啊,了解了.

现在我还是把tar搞到我自己的程序里吧.

现在在解包的时候还有点错误,折腾啊
作者: flw2    时间: 2007-06-06 15:49
你允许该busybox?那就很简呀,别改太多,改动不会超过5行
作者: NewCore    时间: 2007-06-06 15:50
原帖由 flw2 于 2007-6-6 15:44 发表于 47楼  
我有源码,这些不都是公开的吗。busybox里的tar也有个main函数呀,你在关键地方检察一下,比如
if (argv == "tar")
setbuf NULL



恩啊,我明白了

实在不行,我可以直接把busybox里面的tar_main里面加上setbuf NULL,然后把tar命令生成后copy到我们自己的系统上,我们系统上的命令本来也就是用busybox生成的....
作者: NewCore    时间: 2007-06-06 15:51
to flw2

应该是这样的吧.?
作者: flw2    时间: 2007-06-06 15:54
放在tar_main不一定可以,如果以前没有printf确实可以

你要是很自由的改代码,直接main函数前面加个setbuf也没有什么关系

不过个人认为你的做法实在是不可取
作者: NewCore    时间: 2007-06-06 16:00
原帖由 flw2 于 2007-6-6 15:54 发表于 52楼  
放在tar_main不一定可以,如果以前没有printf确实可以

你要是很自由的改代码,直接main函数前面加个setbuf也没有什么关系

不过个人认为你的做法实在是不可取



这作为最后的办法把,我现在还是先把tar搞到我自己的代码里,这样应该是现在比较合适的解决办法了.

多谢你的回复,遇上这样的问题,郁闷死我了,都说蛮简单个事,我做了一个星期了....
作者: MMMIX    时间: 2007-06-06 16:16
原帖由 NewCore 于 2007-6-6 16:00 发表于 53楼  



这作为最后的办法把,我现在还是先把tar搞到我自己的代码里,这样应该是现在比较合适的解决办法了.

多谢你的回复,遇上这样的问题,郁闷死我了,都说蛮简单个事,我做了一个星期了....

因为你一直坚持要用 system 函数。
作者: NewCore    时间: 2007-06-06 16:19
原帖由 MMMIX 于 2007-6-6 16:16 发表于 54楼  

因为你一直坚持要用 system 函数。






老大说的是,我承认我可能是有点转牛角尖了,但是system并不是问题的关键吧...
作者: MMMIX    时间: 2007-06-06 16:23
原帖由 NewCore 于 2007-6-6 16:19 发表于 55楼  






老大说的是,我承认我可能是有点转牛角尖了,但是system并不是问题的关键吧...

这个我觉得你错了。system 会启动一个 shell 来执行你的命令,天知道这个 shell 都会做些什么。
作者: mirnshi    时间: 2007-06-06 19:25
用unix-socket,测试了一下,可以得到输出。
server: 打开socket, system执行客户端,等待客户端的输入
client: 打开socket,建立连接,然后复制到0,1,2句柄上,再exec执行tar,服务端就可以读到tar的输出了。
作者: NewCore    时间: 2007-06-06 22:48
原帖由 mirnshi 于 2007-6-6 19:25 发表于 57楼  
用unix-socket,测试了一下,可以得到输出。
server: 打开socket, system执行客户端,等待客户端的输入
client: 打开socket,建立连接,然后复制到0,1,2句柄上,再exec执行tar,服务端就可以读到tar的输出了。



一般情况下,这样做是肯定没有问题的。我代码在redhat9上也跑得好好的,但是到了我们板子上的系统上就搞不定了...

其实,很多时候时间都耗在这些意外上,如果事事都在“一般情况下”,那这个世界就太完美了...
作者: ulovko    时间: 2012-04-26 14:54
跟大家学习真好!




欢迎光临 Chinaunix (http://bbs.chinaunix.net/) Powered by Discuz! X3.2