C/UNIX从输入读取(受字符计数和超时限制)



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

程序将stdin读取到缓冲区(固定大小)。当缓冲区已满时,程序会将其打印到文件中。但若缓冲区并没有在固定时间(超时)内填满,程序将打印到文件[TIMEOUT]和缓冲区的其余部分(当前已读取)

第一个例子:

buffer_size=5;timeout=4;

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

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

第二个例子

buffer_size=3;timeout=5;

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

应该写入111 111 111等,因为当循环写入3个字符时(在3秒内<5秒限制),所以永远不会发生超时。

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

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

有人能告诉我吗?我不知道如何处理这种行为,邻居stackoverflow和谷歌都给了我答案(或者我只是不知道该搜索什么)

提前感谢

以下是一些提示:

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

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

谢谢大家,我用其他方式解决了这个问题(但仍然没有忙着等待)。我附上下面的代码供进一步的学生使用:)

#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 %dn", 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);
}

相关内容

  • 没有找到相关文章

最新更新