使 C++ 不等待用户输入

Make c++ not wait for user input

本文关键字:用户 输入 等待 C++      更新时间:2023-10-16

所以,我正在尝试做一个c ++ WinSock2的聊天,只是为了学习。这是一个控制台应用程序,我想接受用户输入(用于发送给对应方(,但我仍然希望能够接收。(因此,您可以在仍然能够接收消息的同时编写消息(...

当使用cin >> input;程序"暂停"直到用户输入某些内容时,这样它是"基于回合的"(一个用户编写内容并发送它,然后另一个用户写入某些内容并发送它(。

有没有办法让用户能够在接收内容仍在运行时编写一些东西?(最好是多线程以外的其他东西(

检查缓冲区是否为空怎么样?但是代码不会真正可移植,因为据我所知,您需要进行一些系统调用。看到这里。
但也许你可以用一些 C 代码来做,我会做一些研究并更新我的答案。

UPD:好的,我做到了。您需要的是选择功能。
它可以等到stdin准备好阅读,这就是我们所需要的。但看起来它不适用于C++流,因此您只需要使用 C 代码进行读取。

让我们跳到定义:
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *errorfds, struct timeval *timeout)

好的,我们只需要检查读取缓冲区,因此可以NULL writefdserrorfds。我们只需要检查stdin,所以nfds1(fds es的数量(

超时呢?它应该是0的,所以我们需要初始化变量struct timeval timeout,并通过timeout.tv_sec = 0timeout.tv_usec = 0将秒和纳秒设置为0。

所以,只剩下readfds了。这也很简单:我们需要初始化变量,将其"归零",然后添加stdin
它可以通过fd_set readfdsFD_ZERO(&readfds)FD_SET(STDIN_FILENO, &readfds)来完成。

好的,最后一步:函数调用。应该是select(1, &readfds, NULL, NULL, &timeout).

如果输入缓冲区为空,这将返回0,如果不是,则返回1

UPD2:看起来它不是C++流,发生了一些奇怪的事情,当缓冲区在第一次调用时为空时它会中断。我会尝试抓住问题。

UPD3:好的,现在我想通了。看起来您可以将select与C++流一起使用。

Select具有非常奇怪(恕我直言(的功能:它会重置readfds。我不确定如何防止它这样做,所以我只是再用一个fd_set变量来保存它,所以你需要在readfds初始化后添加fd_set savefds = readfds,并在每次调用后添加readfds = savefds。这是一个糟糕的解决方案,但我不知道如何改进它。

所以代码是:

初始化:

fd_set readfds;
FD_ZERO(&readfds);
FD_SET(STDIN_FILENO, &readfds);
fd_set savefds = readfds;  

超时初始化:

struct timeval timeout;
timeout.tv_sec = 0;
timeout.tv_usec = 0;

和用法:

if (select(1, &readfds, NULL, NULL, &timeout)) {
  cin >> input;
  send(input);
}
readfds = savefds;

UPD4:不要忘记包括unistd.hcstdlib

上面的答案很有帮助。

下面是一个示例(基本代码取自 SELECT 手册页(:

#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <iostream>
int main(void)
{
  fd_set rfds, save_rfds;
  struct timeval tv;
  int retval;
  /* Watch stdin (fd 0) to see when it has input. */
  FD_ZERO(&rfds);
  FD_SET(0, &rfds);
  /* Make a copy of rfds, as after running select, it gets reset */
  save_rfds = rfds;
  /* Wait for zero seconds. */
  tv.tv_sec = 0;
  tv.tv_usec = 0;
  while(true){
    retval = select(1, &rfds, NULL, NULL, &tv);
    rfds = save_rfds;
    if (retval == -1)
      perror("select()");
    else if (retval){
      /* Runs as soon as you enter a value and press enter. */
      std::cout<<"Data is available now.n";
      std::string s;
      getline(std::cin, s);
      std::cout<<"Data Input: "<<s<<"n";
      /* FD_ISSET(0, &rfds) will be true. */
    }
  }
  exit(EXIT_SUCCESS);
}