有关fgets和fcntl的讨论-待整理更新
阅读原文时间:2023年07月08日阅读:2

问题引出

一个client程序:select 超时监听 sockfd套接字 和 STDIN_FILENO标准输入:若sockfd可读则接收server报文;若标准输入可读(按下回车),则开始用fgets/fscanf等函数从标准输入捕获字符后发送给server;若select 2秒超时,client发送一次心跳包给server。要求不能开其他的进程或线程,也不能使用定时器和信号,即单线程client。

现在问题来了,在使用fgets/fscanf时,会阻塞select函数,这样一来client就无法进入超时流程发送心跳包;若将标准输入设置为非阻塞,那么fgets/fscanf立即返回,捕获的内容为空,达不到要求。

        请问,有没有一种方法能让程序一边等待fgets/fscanf的捕获,一边循环非阻塞执行select函数?

尝试方法

用过linux下实现的kbhit,若没有按键输入则跳出这个函数,有输入则getchar到一个数组中存放然后退出函数,若捕获到回车键再把数组内容填充到发送报文。这样就是一个非阻塞的输入函数。

        case1:select还是监听标准输入,只有按下回车键,程序才可能进入select的标准输入可读流程。这样要想输入一个字符必须先敲一个回车,显然不行。

        case2:select不监听标准输入,在循环中,先执行select,再执行kbhit。这种方式能行,但是响应太慢,因为select是2秒超发心跳,所以select是半阻塞的,也就是说要想执行kbhit,必须等待2秒。

最终放弃此方法。

在进行select循环之前就把要输入的内容提前录入,然后回车。之后程序进入到select的标准输入可读流程,在这里使用fgets将之前录入的内容全部读入一个buf[],然后解析字符串,填入到发送报文;即只要不输入回车键,程序就无法进入select的标准输入可读流程,自然不会影响2秒超时发保活包。

这种方法实验效果能达到题目要求。

fgets为行缓存IO函数,遇到回车键才把处理缓冲中的数据流。将标准输入流stdin改为无缓冲方式,这样只要有字符敲入(即使没有敲入回车)select就会监听到标准输入可读。在相应流程中使用getchar()将捕获的输入存放于buf[],然后退出流程继续监听。若捕获到0x0a,表明输入的结束,之后同方法2一样解析和发送。

这种方法实验效果也能达到题目要求。

手机扫一扫

移动阅读更方便

阿里云服务器
腾讯云服务器
七牛云服务器