I am trying to modify an example I found.
The example:
#include <stdio.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#define STDIN 0 // file descriptor for standard input
int main(void)
{
struct timeval tv;
fd_set readfds;
tv.tv_sec = 2;
tv.tv_usec = 500000;
FD_ZERO(&readfds);
FD_SET(STDIN, &readfds);
// don't care about writefds and exceptfds:
select(STDIN+1, &readfds, NULL, NULL, &tv);
if (FD_ISSET(STDIN, &readfds))
printf("A key was pressed!\n");
else
printf("Timed out.\n");
return 0;
}
Which print time out if 2.5 seconds has passed without sending a message, otherwise printing a key was pressed.
I tried to put it inside a while loop:
#include <stdio.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#define STDIN 0 // file descriptor for standard input
int main(void)
{
fd_set readfds, temp;
struct timeval tv;
FD_ZERO(&readfds);
FD_ZERO(&temp);
FD_SET(STDIN, &readfds);
while(1){
temp = readfds;
tv.tv_sec = 2;
tv.tv_usec = 500000;
// don't care about writefds and exceptfds:
if (select(STDIN+1, &temp, NULL, NULL, &tv) == -1)
printf("err");
if (FD_ISSET(STDIN, &temp))
{
printf("A key was pressed!\n");
}
else
printf("Timed out.\n");
}
return 0;
}
In this code when I enter a key it keeps printing a key was pressed forever.
I read online the I have to set tv variable every time but still no help.
Do i need a temp fd_set
? what am I wrong ?
#include <stdio.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <errno.h>
// Note: STDIN_FILENO, or fileno(stdin)
#define STDIN 0 // file descriptor for standard input
int main(void)
{
fd_set readfds, temp;
struct timeval tv;
int ret,ch;
FD_ZERO(&readfds);
FD_ZERO(&temp);
FD_SET(STDIN, &readfds);
while(1){
temp = readfds;
tv.tv_sec = 2;
tv.tv_usec = 500000;
// don't care about writefds and exceptfds:
ret = select(STDIN+1, &temp, NULL, NULL, &tv) ;
if (ret == -1) {
if (errno == EAGAIN) continue; // These are NOT Errors, but natural occuring events
if (errno == EINTR) continue; // The are reported to avoid your select() to block for too long
perror("erreur");
break;
}
else if (ret ==0) {
printf("Timed out.\n");
continue;
}
// Ok: select has returned > 0; there must be something to read
if (FD_ISSET(STDIN, &temp)) {
ch = getc(stdin); // Lookout: stdin is line-buffered
printf("A key was pressed: %d!\n", ch);
}
}
return 0;
}
Related
I have to write a program which monitors two named pipes and prints the information sent through either.
When the write end of one of the pipes is closed, the program will detect this and close and open the pipe again.
This is what I have written so far:
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#define BUF_SIZE 200
int
main(void)
{
fd_set rfds;
struct timeval tv;
int retval;
ssize_t n_read;
char buf[BUF_SIZE];
/* Open pipes */
int tuberia1_fd = open("tuberia1",O_RDONLY);
int tuberia2_fd = open("tuberia2",O_RDONLY);
while(1){
/* Watch stdin (fd 0) to see when it has input. */
FD_ZERO(&rfds);
FD_SET(0, &rfds);
/* Wait for an indefinite amount of time. */
tv.tv_sec = 0;
tv.tv_usec = 0;
retval = select(2, &rfds, NULL, NULL, &tv);
/* Don't rely on the value of tv now! */
if (retval == -1)
perror("select()");
exit(EXIT_FAILURE);
if(FD_ISSET(tuberia1_fd, &rfds)){
n_read = read(tuberia1_fd, &buf, BUF_SIZE);
if (n_read == 0){
close(tuberia1_fd);
tuberia1_fd = open("tuberia1", O_RDONLY);
}else{
buf[n_read] = '\0';
printf("tuberia1: %s", buf);
}
} else if (FD_ISSET(tuberia2_fd, &rfds)){
n_read = read(tuberia2_fd, &buf, BUF_SIZE);
if (n_read == 0){
close(tuberia2_fd);
tuberia2_fd = open("tuberia2", O_RDONLY);
}else{
buf[n_read] = '\0';
printf("tuberia2: %s", buf);
}
}
}
}
When I run it, the program locks, which is the expected behavior. But when I echo hello_world > tuberia1 there is no response from the program.
What is going on?
EDIT: As observed by GM below, I was incorrectly passing arguments to select. After fixing that my program looks like this:
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#define BUF_SIZE 200
int
main(void)
{
fd_set rfds;
struct timeval tv;
int retval;
ssize_t n_read;
char buf[BUF_SIZE];
/* Open pipes */
printf("Opening tuberia1");
int tuberia1_fd = open("tuberia1",O_RDONLY);
printf("Opening tuberia2");
int tuberia2_fd = open("tuberia2",O_RDONLY);
while(1){
printf("Enter the loop");
/* Watch stdin (fd 0) to see when it has input. */
FD_ZERO(&rfds);
FD_SET(tuberia1_fd, &rfds);
FD_SET(tuberia2_fd, &rfds);
/* Wait for an indefinite amount of time. */
tv.tv_sec = 5;
tv.tv_usec = 0;
int fd_max = (tuberia1_fd > tuberia2_fd) ? tuberia1_fd : tuberia2_fd;
retval = select(fd_max, &rfds, NULL, NULL, &tv);
/* Don't rely on the value of tv now! */
if (retval == -1)
perror("select()");
exit(EXIT_FAILURE);
if(FD_ISSET(tuberia1_fd, &rfds)){
n_read = read(tuberia1_fd, &buf, BUF_SIZE);
if (n_read == 0){
close(tuberia1_fd);
tuberia1_fd = open("tuberia1", O_RDONLY);
}else{
buf[n_read] = '\0';
printf("tuberia1: %s", buf);
}
} else if (FD_ISSET(tuberia2_fd, &rfds)){
n_read = read(tuberia2_fd, &buf, BUF_SIZE);
if (n_read == 0){
close(tuberia2_fd);
tuberia2_fd = open("tuberia2", O_RDONLY);
}else{
buf[n_read] = '\0';
printf("tuberia2: %s", buf);
}
}
}
}
It still does not work. Running it under GDB shows that the program never progresses past the first open.
You need to use FD_SET on the file descriptors you're actually interested in -- namely tuberia1_fd and tuberia2_fd.
So something like...
while (1) {
FD_ZERO(&rfds);
FD_SET(tuberia1_fd, &rfds);
FD_SET(tuberia2_fd, &rfds);
int max;
if (tuberia1_fd > tuberia2_fd) {
max = tuberia1_fd;
} else {
max = tuberia2_fd;
}
tv.tv_sec = 0;
tv.tv_usec = 0;
retval = select(max + 1, &rfds, NULL, NULL, &tv);
Running this snippet of code to experiment with piping and signals. I'm trying to learn how to properly utilize the select() function between pipes.
This process will fork. If there is something to be read from stdIn it is then written to the write end of the pipe. It is supposed to execute either a basic command entered via terminal, or it runs hard-coded commands in the code. (It's running hard code right now as "ls.")
When I run this snippet, it should quit and stop running completely when I press the letter "q" followed by ENTER, or it should quit after it runs its assigned process.
Instead, even after I hit "q" or run the process it won't stop the program completely. It is still waiting for input. It will stop running once I have hit ENTER, but it never even executes my process.
For example, if I compile and run this as "./test ls" or even just run "./test" (because ls is hard-coded in so that SHOULD just run I think), it will not run the command ls. And the program will continue to run until I've hit ENTER again.
I'm certain my rudimentary understanding of select() has to do with this issue. I'm pretty sure my select() statement needs to break at some point but I don't know what or how to check for this.
I was told that there is a method WIFEXITED() that might be able to help me but I'm just not sure how it applies in this context.
I also would like to know how to check if your pipes are empty!
I DO know that I want this to be able to both take input from the terminal and record it and also run built in functions.
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <sys/select.h>
#include <stdio.h>
int main() {
int in[2]; // parent writes; child reads
pipe(in);
if (fork() == 0) {
// instantiate the values that will be execed
char *a[2];
//a[0] = "./test3";
a[0] = "ls";
a[1] = NULL;
// redirects what is being read from stdin to the pipe
//this redirection is for a separate test that is not included
close(in[1]);
close(0);
dup(in[0]);
close(in[0]); // close read
execvp(a[0], a);
}
else {
close(in[0]); // only want parent to write
// select() params
int nfds = 3;
int check = -1;
int done = 0;
fd_set readfds;
fd_set writefds;
FD_ZERO(&readfds); // set select params
FD_SET(0, &readfds);
FD_SET(in[1], &writefds);
while ((check = select(nfds, &readfds, &writefds, NULL, NULL)) > 0) {
int size = 0;
char buf[1000];
// write to pipe for child
if (FD_ISSET(0, &readfds) && FD_ISSET(in[1], &writefds)) {
while ((size = read(0, buf, sizeof(buf))) != 0) {
write(in[1], buf, size);
}
}
// reset
FD_ZERO(&readfds);
FD_SET(0, &readfds);
FD_SET(in[1], &writefds);
}
printf("%d --------------- %d\n", (FD_ISSET(in[1], &writefds)),
FD_ISSET(0, &readfds));
}
return 0;
}
Here is the potential set of test code that can be run with the above snipped if a[0] = ./test is uncommented and a[0] = ls is commented.
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <sys/select.h>
int main () {
int fd;
char buf[11];
int ret, sret;
int flag = 0;
fd = 0;
fd_set readfds;
struct timeval timeout;
while(1) {
FD_ZERO(&readfds);
FD_SET(fd, &readfds);
timeout.tv_sec = 5;
timeout.tv_usec = 0;
sret = select(fd + 1, &readfds, NULL, NULL, NULL);
memset((void *) buf, 0, 11);
ret = read(fd, (void *) buf, 10);
flag = strcmp(buf, "q\n") == 0;
if (flag) {
return 0;
}
printf("ret = %d\n", ret);
if(ret != -1) {
printf(" buf = %s\n", buf);
}
}
return 0;
}
I'm implementing a simple ipc system using linux named pipes in C.
I have this server code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include "external/paths.h"
#include "external/sv.h"
#include "external/tags.h"
int main(int argc, char *argv[])
{
int fd, bytes_read;
char request[200];
// create fifo
mknod(FIFO_SERVER, S_IFIFO | 0666, 0);
puts("Servidor initialized.\nWaiting for client requests.");
// open created fifo
fd = open(FIFO_SERVER, O_RDONLY);
while(1)
{
if( (bytes_read = read(fd, request, LEN_CL_REQUEST)) == -1 )
perror("error read()");
if(bytes_read == 0)
continue;
if(bytes_read > 0)
{
printf("Request read: %s\n", request);
// answer back
}
}
close(fd);
unlink(FIFO_SERVER);
return 0;
}
I'm ommiting the client because my question is only related with the server. The communication is working fine, I can read requests from the client and I can answer them. Now, lets say I want to, at anytime, be able to quit the server when the key 'Q' is pressed.. I can't do this because my code blocks on the read statement waiting for another client request, so I have no way to read the stdin..
Is something like this possible to do? I'm thinking in something like non-blocking the read statement and try to read stdin for a few seconds, then check again for incoming requests.. I've been searching but I haven't found anything similar.
UPDATE:
I followed Jean-Baptiste Yunès approach but it turns out that select is only detecting the fifo events, I don't really know why.
This is the code I'm testing:
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main()
{
int result, fd, maxDescriptor;
char input[20], texto[100];
mknod("fifo", S_IFIFO | 0666, 0);
fd = open("fifo", O_RDWR); // RDWR to avoid EOF return to select
fd_set readset;
FD_ZERO(&readset);
FD_SET(fileno(stdin), &readset);
FD_SET(fd, &readset);
maxDescriptor = fileno(stdin) > fd ? fileno(stdin) : fd;
while(1)
{
result = select(maxDescriptor+1, &readset, NULL, NULL, NULL);
if(result == -1)
perror("select()");
else if(result)
{
puts("data available.");
if( FD_ISSET(fileno(stdin), &readset) )
{
scanf("%s", input);
printf("%s\n", input);
if( strcmp(input, "Q") == 0 )
break;
}
if( FD_ISSET(fd, &readset) )
{
read(fd, texto, 100);
printf("lido:\n%s\n", texto);
}
}
else
puts("no data.");
}
unlink("fifo");
return 0;
}
UPDATE 2:
As Jean-Baptiste Yunès pointed out, there's need to reset fd_set since it doesn't reset automatically.
Here's the final working code:
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main()
{
int result, fd, maxDescriptor;
char input[20], texto[100];
mknod("fifo", S_IFIFO | 0666, 0);
fd = open("fifo", O_RDWR); // RDWR to avoid EOF return to select
fd_set readset;
FD_ZERO(&readset);
FD_SET(fileno(stdin), &readset);
FD_SET(fd, &readset);
maxDescriptor = fileno(stdin) > fd ? fileno(stdin) : fd;
while(1)
{
result = select(maxDescriptor+1, &readset, NULL, NULL, NULL);
if(result == -1)
perror("select()");
else if(result)
{
puts("data available.");
if( FD_ISSET(fileno(stdin), &readset) )
{
scanf("%s", input);
printf("%s\n", input);
if( strcmp(input, "Q") == 0 )
break;
}
if( FD_ISSET(fd, &readset) )
{
read(fd, texto, 100);
printf("lido:\n%s\n", texto);
}
FD_SET(fileno(stdin), &readset);
FD_SET(fd, &readset);
}
else
puts("no data.");
}
unlink("fifo");
return 0;
}
You have to use select. You need to wait on both channels: something from the pipe or something from stdin but you never know which one to read. The purpose of select is to make your process wait on any channel for read or write.
fd_set readset;
FD_ZERO(&readset); // empty set of descriptor to select on
FD_SET(fd, &readset); // add the pipe
FD_SET(stdin, &readset); // add stdin
result = select(fd + 1, &readset, NULL, NULL, NULL); // now wait for something to read on at least one channel (pipe or stdin)
if (result>0) {
if (FD_ISSET(fd, &readset)) { // test for pipe availability
// now read the pipe
}
if (FD_ISSET(stdin, &readset)) { // test for stdin availability
// now read stdin
}
}
So, I want this program to wait for 5 seconds for an input. If there is no input it returns. If there is input, it renews the timer and starts the count again.
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
int main(void)
{
fd_set rfds;
struct timeval tv;
int retval;
char buf[1024];
/* Watch stdin (fd 0) to see when it has input. */
FD_ZERO(&rfds);
FD_SET(0, &rfds);
/* Wait up to five seconds. */
do {
tv.tv_sec = 5;
tv.tv_usec = 0;
printf("Please enter a number: \n");
retval = select(1, &rfds, NULL, NULL, &tv);
/* Don't rely on the value of tv now! */
if (retval == -1)
perror("select()");
else if (retval) {
scanf("%[^\n]%*c", buf);
}
else
printf("No data within five seconds.\n");
} while (tv.tv_sec != 0 && tv.tv_usec != 0);
exit(EXIT_SUCCESS);
}
It works fine with regular input, but when I press enter twice, it goes into infinite loop. Why? What is happening?
You need to put FD_SET(0, &rfds); within the loop...
... if it select times out, the rfds structure will be reset
as if FD_ZERO() had been called....
Additionally, I might suggest you change the scanf() to a more simple fgets() if moving the FD_SET() doesn't totally solve your problem (in any event, FD_SET needs to be moved).
If I had a while loop that I wanted to stop only if the q key is pressed how would I do that.
However, I do NOT want it to quite the program
#define TRUE 1
#define FALSE 0
typedef int boolean;
int main(int argc,char* argv[]){
char *script = malloc(MAXPATH);
script = "ls";
boolean a;
a = TRUE;
while(a){ //this is the while loop i want to break incase of a keypress
system(script);
}
do something else
something else....
This will be running on Mac OS X.
both getchar() and getc() pause for a response which makes loop stop
you can use select() mechanism in UNIX-LIKE OS.
all in one function:
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/select.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
fd_set readfds;
struct timeval tv;
int ch;
int bool, ret;
FD_ZERO(&readfds);
bool = 1;
while (bool) {
FD_SET(STDIN_FILENO, &readfds);
tv.tv_sec = 0;
tv.tv_usec = 0;
/* int select(int nfds, fd_set *readfds, fd_set *writefds,
* fd_set *exceptfds, struct timeval *timeout); */
ret = select(STDIN_FILENO + 1, &readfds, NULL, NULL, &tv);
if (ret < 0) {
perror("select error");
exit(1);
} else if (ret == 0) {
/* timeout */
} else if (FD_ISSET(STDIN_FILENO, &readfds)) {
ch = fgetc(stdin);
if (ch == 'q') {
bool = 0;
}
}
sleep(1);
fprintf(stderr, ".");
}
return 0;
}
native functions in C with which i can detect a keypress are :
getchar() and getc()
kbhit() is a function returns integer value whenever the key is pressed
you can use the above functions
#include <stdio.h>
#include <conio.h>
#include <math.h>
#include <time.h>
int main()
{
int m;
clrscr();
do
{
if(kbhit())
{
if((m=getch())==97)
{
printf("Key a is pressed....\n");
}
}
} while(1);
getch();
return 0;
}
I'm glad of alexchandel's answer. I had never heard of poll()
poll() is a good answer for POSIX style systems like the questioner's platform
_kbhit() is the simplest answer on MS Windows. Their Poll() is different of course
The 1 means just one descriptor block in my list, the 100 is milliseconds timout
my file handle is { 0, for stdin
read the man page for the many events you can interrogate, I only wanted POLLIN
#include <stdio.h>
#include <poll.h>
#include <errno.h>
static struct pollfd attention = { 0, POLLIN } ;
int main()
{
int x, y;
for (;;)
{
x = poll(&attention, 1, 100);
if (x < 0)
{
printf("problem %d\n", errno);
break;
}
else if (x)
{
printf("you rang %x ?", x);
y = getc(stdin);
printf(" %c of course\n", y);
if (y == '.') break;
}
}
return 0;
}
You could make the computation run in a pthread while the main loop reads char on stdin. SDL library has better input controls if you don't just want to read char from stdin. gtk also has events that the window receives. The command "xev" is a xlib program for linux that works similarly. It opens a blank window and it reads key events as they come.