LinuxSir.cn,穿越时空的Linuxsir!

 找回密码
 注册
搜索
热搜: shell linux mysql
查看: 1080|回复: 9

使用g_io_channel读取stdin的输入, 应该怎么做?

[复制链接]
发表于 2009-10-30 12:49:43 | 显示全部楼层 |阅读模式
大家好, 我现在有个需求就是读取stdin的输入, 想使用g_io_channel来做, 不知道怎么才能做到.
我的代码如下:

        GIOChannel* gchannel = NULL;
        gchannel = g_io_channel_unix_new(stdin);
        g_io_channel_set_buffer_size (gchannel, 1<<12);
        source_id = g_io_add_watch (gchannel, G_IO_IN|G_IO_OUT|G_IO_PRI|G_IO_ERR|G_IO_HUP|G_IO_NVAL, gchannel_test, NULL);

        mloop = g_main_loop_new(NULL, FALSE);

        g_main_loop_run(mloop);

但是老是报错, 说Invalid file descriptor.
发表于 2009-10-30 13:05:28 | 显示全部楼层
gchannel = g_io_channel_unix_new(stdin);换成
gchannel = g_io_channel_unix_new(fileno(stdin));
回复 支持 反对

使用道具 举报

 楼主| 发表于 2009-10-30 13:42:03 | 显示全部楼层
代码其实很简单, 但是输入以后好像没有输出.

#include <glib.h>
#include <stdio.h>
#include <string.h>

#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>

guint source_id = 0;


gboolean channel_shutdown(GIOChannel *io_channel)
{
        g_source_remove(source_id);
        g_io_channel_shutdown (io_channel, TRUE, NULL);
        g_io_channel_unref (io_channel);
}
gboolean gchannel_test(GIOChannel *source, GIOCondition condition, gpointer data)
{
        if (condition & G_IO_IN)
        {
                int fp = g_io_channel_unix_get_fd(source);
                char buffer[1<<10];
                int len;
                while (0<(len=read(fp, buffer, 1023)))
                {
                        buffer[len] = 0;
                        if (strstr(buffer, "end"))
                        {
                                channel_shutdown(source);
                        }
                        g_printf("got:%s", buffer);
                }
        }
        else if (condition & (G_IO_HUP | G_IO_ERR | G_IO_NVAL))
        {
                g_printf("we are going to shutdown the channel now.");
                channel_shutdown(source);
        }
}
int     main(int argc, char *argv[])
{
        GMainLoop *mloop;

        GIOChannel* gchannel = NULL;
        int fd = 0; //the stdin??? open("/dev/pts/1", O_RDONLY);


        gchannel = g_io_channel_unix_new(fileno(stdin));
        g_io_channel_set_buffer_size (gchannel, 1<<12);
        source_id = g_io_add_watch (gchannel, G_IO_IN|G_IO_OUT|G_IO_PRI|G_IO_ERR|G_IO_HUP|G_IO_NVAL, gchannel_test, NULL);

        mloop = g_main_loop_new(NULL, FALSE);

        close(fd);
        g_main_loop_run(mloop);

        return 0;
}
回复 支持 反对

使用道具 举报

发表于 2009-10-30 13:55:36 | 显示全部楼层
close(fd)应该放在
g_main_loop_run(mloop)
之后。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2009-10-30 14:06:48 | 显示全部楼层
还是没有输出啊, 是还有哪里没有注意到么.
谢谢realtang
回复 支持 反对

使用道具 举报

 楼主| 发表于 2009-10-30 15:10:08 | 显示全部楼层
对不起,
前面没有说清楚, 我用的是远程的客户端,ssh登录进去的.

有没有可能是stdin只针对一个标准键盘输入?
但是我搜到的一些帖子上说, 每个进程都有自己的一套stdin/stdout/stderr的啊
回复 支持 反对

使用道具 举报

 楼主| 发表于 2009-10-31 10:03:16 | 显示全部楼层
有人能帮忙解决一下吗
其实我可以用socket来做iochannel的, 但想知道为什么stdin不行.
回复 支持 反对

使用道具 举报

发表于 2009-11-2 12:14:26 | 显示全部楼层
在讨论这个问题之前, 先做几方面细节的调整吧:

* 首先 watch 中就不要把 OUT 也加进去了, 否则会由于 OUT 一直有效而不停地空跑.
* 另外, watch 的 callback 中, return 语句不可以省略, 它直接决定了 callback 是否会继续调用. 不写的话, 系统可能会从栈中得到不正确的返回结果, 从而非预期地结束了回调.

综合以上两项, 当 IN 发生之前 callback 可能已经由于 OUT 而被调用过了, 而又由于刚好随机返回了 FALSE 从而 callback 被取消, 之后发生的 IN 已经不再被 watch 了.
回复 支持 反对

使用道具 举报

 楼主| 发表于 2009-11-2 13:50:03 | 显示全部楼层
谢谢remote fish, 现在工作起来了, 我确实忘了要返回true.

有几个不明白的地方还望指点:

1. stdin应该是只读文件, 为什么G_IO_OUT会一直有效.

2. 在读取输入的时候, stdin的输入不是缓冲的么, 我在函数中使用                while (0<(len=read(fp, buffer, 1023)))
的本意是读取用户当前所有输入, 但是这个函数好像会阻塞等待用户输入. 这样的话, 事件循环也就阻塞住了. 如何避免这种情况呢.
回复 支持 反对

使用道具 举报

发表于 2009-11-3 13:12:25 | 显示全部楼层
Post by mrstupid;2042003
谢谢remote fish, 现在工作起来了, 我确实忘了要返回true.

有几个不明白的地方还望指点:

1. stdin应该是只读文件, 为什么G_IO_OUT会一直有效.

2. 在读取输入的时候, stdin的输入不是缓冲的么, 我在函数中使用                while (0<(len=read(fp, buffer, 1023)))
的本意是读取用户当前所有输入, 但是这个函数好像会阻塞等待用户输入. 这样的话, 事件循环也就阻塞住了. 如何避免这种情况呢.


1 的问题, 抱歉我也不知道系统内部是如何处理的.

2 的问题, 如果楼主打算使用非 channel 的接口来读取数据的话, 建议先把 channel 设置为非缓冲的 (不过对于 stdin 是否能正确完成这样的操作我不太确定), 否则 channel 内部的缓冲会导致很多问题. 或者, 仅使用 channel 的相关接口来读取数据. 无论使用哪一种方法, 也不应该在 channel 中进行楼主这样的 while() 循环, 而应该只读取一次后就直接 return, 如果还有数据, 那么 watch callback 会继续被调用, 直到数据读完. 如果一定要在一次 callback 中读取尽量多的数据, 那么至少每一次 read() 前用 poll() 或者 select() 判断一下是否还有数据. 但其实也许楼主会愿意试一试 g_io_channel_read_to_end() 函数.
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 返回顶部 返回列表