使c ++不等待用户输入

时间:2015-12-27 11:06:46

标签: c++ input chat winsock winsock2

所以,我正在尝试进行c ++ WinSock2聊天,只是为了学习。 它是一个控制台应用程序,我想接受用户输入(发送给对方),但我仍然希望能够回复。 (所以你可以写一条消息,同时仍然能够回复一条消息)......

当使用cin >> input;时,程序“暂停”直到用户输入了某些东西,这样它就是“回合制”(一个用户写东西并发送它,然后另一个用户写东西并发送它)。

有没有办法让用户能够在recive的东西仍在运行时写点东西? (最好不要多线程)

2 个答案:

答案 0 :(得分:3)

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

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

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

好的,我们只需要检查读取缓冲区,因此writefdserrorfds可以是NULL。我们只需要检查stdin,因此nfds1fds 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变量来保存它,因此您需要在fd_set savefds = readfds初始化后添加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

答案 1 :(得分:0)

above answer很有帮助。

以下是示例(来自SELECT man page的基本代码):

#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);
}