【问题标题】:C/UNIX read from input (limited by char count and timeout)C/UNIX 从输入读取(受字符数和超时限制)
【发布时间】:2014-02-08 12:03:45
【问题描述】:

在准备期末考试时,我发现了一个非常有趣的任务。这就是我想要编写的代码。

程序将标准输入读入缓冲区(固定大小)。当缓冲区已满时,程序将其打印到文件中。但是如果缓冲区没有在固定时间(超时)被填充,程序将打印到文件[TIMEOUT] 和缓冲区的其余部分(当前读取)

第一个例子:

buffer_size = 5;超时 = 4;

$ while : ; do printf 1; sleep 1; done | ./a.out

应该写 [TIMEOUT]1111[TIMEOUT]1111[TIMEOUT]1111 等,因为 while 循环只写 4 个字符(在 4 秒内)。

第二个例子

buffer_size = 3;超时 = 5;

$ while : ; do printf 1; sleep 1; done | ./a.out

应该写 111 111 111 等,因为 while 循环写入 3 个字符(在 3 秒

我正在尝试使用poll 对其进行编码,但我不知道如何找出是所有字符都已写入还是仅一个字符。我也不能卡在read(0, buffer, buffer_size) 上,因为我会错过超时。甚至可能吗?我想这就像我们的老师指出的那样是一个很好的练习。

当然,忙等待是不可接受的,只允许经典的 POSIX 系统调用(轮询、选择、读取、写入、打开...)。

有人可以提示我吗?我不知道如何管理这种行为,并且更近的 stackoverflow 和谷歌都给了我答案(或者我可能只是不知道要搜索什么)

提前致谢

【问题讨论】:

标签: c unix timeout buffer polling


【解决方案1】:

这里有一些提示:

  1. 使用 select() 超时
  2. 将 FD 设置为 O_NONBLOCKfcntl
  3. 仅当 FD_ISSET 返回 true 时从 FD 读取
  4. 读到EWOULDBLOCKEAGAIN(表示超时)。如果看到EINTR,请重复循环。

这里有一个更好的答案:去你的图书馆,把斯蒂芬斯的副本拿出来。我相信是这本书: http://www.amazon.com/Programming-Environment-Addison-Wesley-Professional-Computing/dp/0321637739 你想要(他的都很棒)。然而,这仍然是教你如何做这些事情的规范参考书,应该是你课程的核心文本。

【讨论】:

  • 感谢提示,但它实际上不起作用(至少我的实现)......我将发布代码以供大家查看。
【解决方案2】:

谢谢大家,我以其他方式想通了(但仍然没有忙等待)。我附上下面的代码供更多的学生使用:)

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <strings.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <libgen.h>
#include <err.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <arpa/inet.h>
#include <time.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/poll.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <errno.h>

extern char ** environ;

/*
usage:

$ while : ; do printf 1; sleep 1; done | XTIMEOUT=4 XSIZE=5 ./a.out
[TIMEOUT]1111[TIMEOUT]1111[TIMEOUT]1111...

$ while : ; do printf 1; sleep 1; done | XTIMEOUT=5 XSIZE=3 ./a.out
111...
*/

uint64_t
now()
{
    struct timeval tv;
    gettimeofday(&tv, NULL);
    double time_in_mill =  (tv.tv_sec) * 1000 + (tv.tv_usec) / 1000;
    return (uint64_t) time_in_mill;
}

int
main(int argc, char ** argv) { 

    //  ----------------------------------
    //  boring stuff

    size_t timeout = 11 * 1000;
    size_t buffer_size = 10;

    char * tmp_env;
    if ((tmp_env = getenv("XTIMEOUT")) != NULL) {
        timeout = atoi(tmp_env) * 1000;
    }
    if ((tmp_env = getenv("XSIZE")) != NULL) {
        buffer_size = atoi(tmp_env);
    }

    //  ----------------------------------
    //  fun starts here

    //  buffers
    char * buffer = (char *) malloc(buffer_size * sizeof(char));
    char * buffer2 = (char *) malloc(buffer_size * sizeof(char));

    //  set stdin non-blocking
    int saved_flags = fcntl(0, F_GETFL);
    fcntl(0, saved_flags | O_NONBLOCK);


    //  poll structure
    struct pollfd ufds[1];
    ufds[0].fd = 0;
    ufds[0].events = POLLIN;

    int rv, n, k;
    size_t pos = 0;
    uint64_t start_time;

    int rem_time = timeout;

    for (;;) {
        start_time = now();
        //printf("pollig for %d\n", rem_time);
        rv = poll(ufds, 1, rem_time);

        if (rv == -1) {     //  err
            err(1, "poll");
        }
        else if (rv == 0) { //  timeout
            write(1, "[TIMEOUT]", 9);
            write(1, buffer, pos);
            pos = 0;
            rem_time = timeout;
        }
        else {      //  regular
            if (ufds[0].revents & POLLIN) {     //  real action
                if ((n = read(0, buffer2, buffer_size-pos)) == -1) {    //  read up to free space
                    err(1, "read");
                }

                for (k = 0; k < n; ++k) {   //  copy (maybe strcp)
                    buffer[k+pos] = buffer2[k];
                }

                pos += n;   //  pos has changed

                if (pos == buffer_size) {   //  buffer is full -> write it out and set new timeout
                    write(1, buffer, buffer_size); write(1, "", 1);
                    pos = 0;
                    rem_time = timeout;
                }
                else {      // still not enough, make timeout shorter (by the length of computation)
                    rem_time = rem_time - now() + start_time;
                }
            }
            else {      //  poll failed!
                err(1, "false alarm");
            }
        }
    }

    free(buffer);
    free(buffer2);

    return (0);
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-07-22
    • 2012-09-29
    • 2021-08-21
    • 2018-03-09
    • 1970-01-01
    • 2018-08-05
    • 1970-01-01
    • 2016-11-06
    相关资源
    最近更新 更多