Reputation: 373
I have following code in my chat client:
fd_set fds;
struct timeval t;
t.tv_sec = 0;
t.tv_usec = 100;
int ret;
string message;
while(run)
{
FD_ZERO(&fds);
FD_SET(STDIN_FILENO, &fds);
if((ret = select(STDIN_FILENO + 1, &fds, NULL, NULL, &t)) < 0)
{
exit(ERR_SELECT);
}
else if(ret > 0 && FD_ISSET(STDIN_FILENO, &fds))
{
message.clear();
getline(cin, message);
if(strlen(message.c_str()) > 0)
{
send_message(&message, client_socket);
}
}
}
It works fine when I type something while program is running. It reads message in stdin, sends it and then wait in loop for next input. But when I pass input to program on start like this:
echo "message" | ./chat_client
Or this:
printf "message\n" | ./chat_client
It reads and sends "message" but then in next iterations of loop it behaves like there is something in stdin but getline
reads only empty string. And then when I write something, getline
does not read it.
Does anyone know what causes it?
Thanks for any advice
Upvotes: 1
Views: 1254
Reputation: 6517
getline()
returns if it reaches end-of-file, which happens when everything coming from the pipe has been read. You need to explicitly test if cin.eof()
returns true.
As for select()
it's by design that it shows the file as "readable" if at end-of-file. That way the program can detect the connection was closed. The Linux manual for select()
states that:
A file descriptor is considered ready if it is possible to perform a corresponding I/O operation (e.g., read(2) without blocking...
and a read()
on a file descriptor at EOF returns a zero without blocking.
I'm not sure if you can get problems by selecting on an fd read through an istream, but this works for me (Linux/gcc):
#include <iostream>
#include <sys/select.h>
#include <unistd.h>
int main()
{
std::string message;
while(1) {
fd_set fds;
FD_ZERO(&fds);
FD_SET(STDIN_FILENO, &fds);
int ret = select(1, &fds, NULL, NULL, NULL);
if (ret == -1) break;
getline(std::cin, message);
if (std::cin.eof()) {
std::cout << "eof." << std::endl;
break;
}
std::cout << "read: " << message << std::endl;
}
return 0;
}
Upvotes: 2