非阻塞获取字符 [英] Nonblocking Get Character

查看:204
本文介绍了非阻塞获取字符的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述


  • 平台:Linux 3.2.0的x86(Debian的7)

  • 编译器:GCC 4.7.2(Debian的4.7.2-5)

我写一个函数读取从标准输入一个字符一个字符已经是present的标准输入。如果标准输入是空的功能是假设什么都不做,返回-1。我GOOGLE了非阻塞的输入,并指出民意调查()或的选择()。首先,我想用select(),但我无法得到它的工作,所以我尝试民调(),并得出了相同的结论。我不知道这些功能做的正是但从我了解民意调查()的文档,如果我把它称为像这样:

 结构的pollfd pollfds;
pollfds = STDIN_FILENO;
pollfds.events = POLLIN;
民意调查(pollfds,1,0);

如果(pollfds.revents&安培; POLLIN)如果将真正的数据不是高优先级数据对方可能无阻塞地读。但民意调查()总是超时在我的测试情况。我如何测试功能,可能是问题,但我想要的功能是什么,我测试。这是目前国内功能和测试情况也是如此。

 的#include< poll.h>
#包括LT&;&stdio.h中GT;
#包括LT&;&unistd.h中GT;INT ngetc(字符* C)
{
    结构的pollfd pollfds;
    pollfds.fd = STDIN_FILENO;
    pollfds.events = POLLIN;    轮询(安培; pollfds,1,0);    如果(pollfds.revents&安培; POLLIN)
    {
            //奖励积分的人,可以告诉我,如果
            //阅读()如果有错误将改变* C的价值
            //读取过程中发生
        读(STDIN_FILENO,C,1);
            返回0;
    }
    否则返回-1;
}//试验情况:
//尝试通过与fgets读取留在标准输入一个字符()调用
诠释的main()
{
    INT RET = 0;
    焦C = 0;
    焦炭海峡[256];    //确保输入超过2个字符,这样多余的
    //在标准输入由与fgets左()
    与fgets(STR,2,标准输入);    RET = ngetc(和C);    的printf(RET =%I \\ NC =%C \\ N,RET,C);    返回0;
}


解决方案

您在做IO不当,POSIX说明书和其他所有相关文件明确地说从来没有拌IO上的做FILE * 和文件描述符。你已经很招摇打破了这一规则。这条规则是因为 FILE * 的使用的缓存的,这意味着到的 与fgets 会有什么留给来获得,因为与fgets 已经读过所有未决的数据转换成保存在 FILE * 结构的缓冲

所以,因为没有办法检查一个ISO C IO方法将阻塞,我们只使用文件描述符。

由于我们知道 STDIN_FILENO 仅仅是数字0,我们可以使用

 的fcntl(0,F_SETFL,O_NONBLOCK);

这将关闭所有 S于文件描述符0到非阻塞模式,如果你想使用不同的文件描述符,这样就可以独自离开0那么就使用的 DUP 来复制它。

这样的话,你可以从 调查 完全贯彻 ngetc

  ssize_t供
ngetc(字符* C)
{
  返回读取(0,C,1);
}

或更好,但宏

 的#define ngetc(C)(阅读(0,(三),1))

因此​​,你会得到你正在寻找一个简单的实现。

编辑:如果您还在担心终端缓冲输入,可以随时改变终端的设置,请参阅How禁止在xterm中输入行缓冲的程序?有关如何操作的更多信息。

编辑:,一个不能使用的原因龟etc 而不是是出于同样的原因,使用与fgets 将不起作用。当 FILE *的一个运行 IO功能,它读取从相关文件中描述的所有数据。但是,一旦发生这种情况,调查将永远不会返回,因为它在等待一个文件描述符这总是空的,同样的事情也会与发生读。因此,我建议您按照文档的从不混合的流的意见和的(IO使用与fgets 龟etc 等)的文件描述符的(IO使用等)

  • Platform: Linux 3.2.0 x86 (Debian 7)
  • Compiler: GCC 4.7.2 (Debian 4.7.2-5)

I am writing a function that reads a single character from stdin if a character is already present in stdin. If stdin is empty the function is suppose to do nothing and return -1. I googled nonblocking input and was pointed to poll() or select(). First I tried to use select() but I could not get it to work so I tried poll() and reached the same conclusion. I am not sure what these functions do exactly but from what I understand of poll()'s documentation if I call it like so:

struct pollfd pollfds;
pollfds = STDIN_FILENO;
pollfds.events = POLLIN;
poll(pollfds, 1, 0);

if(pollfds.revents & POLLIN) will be true if "Data other than high-priority data may be read without blocking.". But poll() always times out in my test situation. How I test the function could be the problem but the functionality I want is exactly what I am testing for. Here is the function currently and the test situation as well.

#include <poll.h>
#include <stdio.h>
#include <unistd.h>

int ngetc(char *c)
{       
    struct pollfd pollfds;
    pollfds.fd = STDIN_FILENO;
    pollfds.events = POLLIN;

    poll(&pollfds, 1, 0);

    if(pollfds.revents & POLLIN)
    {
            //Bonus points to the persons that can tell me if
            //read() will change the value of '*c' if an error
            //occurs during the read
        read(STDIN_FILENO, c, 1);
            return 0;
    }
    else return -1;
}

//Test Situation:
//Try to read a character left in stdin by an fgets() call
int main()
{
    int ret = 0;
    char c = 0;
    char str[256];

    //Make sure to enter more than 2 characters so that the excess
    //is left in stdin by fgets()
    fgets(str, 2, stdin);

    ret = ngetc(&c);

    printf("ret = %i\nc = %c\n", ret, c);

    return 0;
}

解决方案

You're doing IO incorrectly, the POSIX manual and all other related documentation explicitly says never to mix IO done on FILE *s and file descriptors. You have very blatantly broken this rule. This rule is in place because FILE *s use buffering an this means that after a call to fgets there will be nothing left for read to get because fgets already read all pending data into a buffer that is kept in the FILE * structure.

So since there's no way to check if an ISO C IO method will block, we have to use file descriptors only.

Since we know that STDIN_FILENO is just the number 0, we can use

fcntl (0, F_SETFL, O_NONBLOCK);

this will turn all reads on file descriptor 0 to non-blocking mode, if you want to use a different file descriptor so that you can leave 0 alone then just use dup to duplicate it.

This way, you can stay away from poll completely and implement ngetc as

ssize_t 
ngetc (char *c)
{
  return read (0, c, 1);
}

or better yet, a macro

#define ngetc(c) (read (0, (c), 1))

Thus you get a simple implementation for what you're looking for.

Edit: If you are still worried about the terminal buffering the input, you can always change the terminal's settings, see How to disable line buffering of input in xterm from program? for more information on how to do this.

Edit: The reason that one could not use fgetc instead of read is for the same reason that using fgets won't work. When one of the FILE * IO functions is run, it reads all the data from the associated file descriptor. But once that happens, poll will never return because it's waiting on a file descriptor that's always empty, and the same thing will happen with read. Thus, I suggest that you follow the advice of the documentation and never mix streams (IO using fgets, fgetc, etc.) and file descriptors (IO using read, write, etc.)

这篇关于非阻塞获取字符的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆