Need help on message passing queue - c++

I'm still new to programming. I have been trying my best to finish this assignment. When I run the program it display: sent of total 0 bytes. It should display total bytes sending out. assignment prompt question:
The Sender:
The sender shall be invoked as ./sender where is the name of
the file to send to the receiver. For example, ./sender file.txt will send the file named
file.txt.
When invoked, the sender shall open the message queue named cpsc351messagequeue. If
it does not exist, the sender shall terminate with an error.
Otherwise, the sender shall open the file specified at the command line and proceed as
follows:
(a) Read at most 4096 bytes from the file.
(b) Send the bytes read through the message queue using mq send() and a message priority of 1.
(c) Repeat the previous steps until the end of file is reached.
(d) When the end of the file is reached, send an empty message to the receiver with a priority of 2 to tell the receiver that the sending is done.
Terminate.
my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <mqueue.h>
#include <unistd.h>
#include <signal.h>
#define MSQ_NAME "/cpsc351queue"
int main(int argc, char** argv)
{
// The file size
int fileSize = -1;
// The buffer used to store the message copied
// copied from the shared memory
char buff[4096];
// The variable to hold the message queue ID
int msqid = -1;
// The total number of bytes written
int totalBytesRead = 0;
// The number of bytes
int bytesRead = 0;
// Whether we are done reading
bool finishedReading = false;
// TODO: Define a data structure
// of type mq_attr to specify a
// queue that can hold up to 10
// messages with the maximum message
// size being 4096 bytes
mq_attr attr;
attr.mq_flags = 0;
attr.mq_maxmsg = 10;
attr.mq_msgsize = 4096;
attr.mq_curmsgs = 0;
// Sanity checks -- make sure the user has provided a file
if(argc < 2)
{
fprintf(stderr, "USAGE: %s <FILE NAME>\n", argv[0]);
exit(1);
}
// Open the file for reading
int fd = open(argv[1], O_RDONLY);
// Make sure the file was opened
if(fd < 0)
{
perror("open");
exit(1);
}
// TODO: Gain access to the message queue
// whose name is defined by the macro
// MSQ_NAME macro above. We assume that
// the receiver has allocated the message queue.
mqd_t qid = mq_open("/cpsc351queue", O_RDWR, 0600, &attr);
//TODO: Loop below attempts to read the
// file 4096 bytes at a time.
// Modify the loop as necessary to send
// each chunk of data read as message
// through the message queue. You can use
// 1 for the priority of the message.
// Keep writing until all data has been written
while((totalBytesRead < fileSize) && !finishedReading)
{
totalBytesRead = read(fd, buff, bytesRead);
bytesRead = mq_send(qid, totalBytesRead, 4096, 1);
// Something went wrong
if(bytesRead < 0)
{
perror("read");
exit(1);
}
// We are at the end of file
else if(bytesRead == 0)
{
// We are at the end of file
finishedReading = true;
}
totalBytesRead += bytesRead;
}
// TODO: Send a message with size of 0
// to the receiver to tell it that the
// transmission is done
fprintf(stderr, "Sent a total of %d bytes\n", totalBytesRead);
// TODO: Close the file
close(fd);
return 0;
}

The program should open the message queue named /cpsc351queue, not /cpsc351messagequeue.
The mq_send function should be called with the following arguments: qid, buff, bytesRead, 1. Currently, it is being called with totalBytesRead, 4096, and 1.
The read function should be called with the following arguments: fd, buff, and 4096. Currently, it is being called with fd, buff, and bytesRead.
The totalBytesRead variable should be updated after the read function is called, not before.
The bytesRead variable should be updated after the mq_send function is called, not before.
The loop should continue until the end of the file is reached, which can be determined by checking whether bytesRead is less than 0. Currently, the loop is continuing until bytesRead is equal to 0.
After the loop finishes, the program should send an empty message to the receiver with a priority of 2 to tell the receiver that the sending is done. This can be done by calling the mq_send function with a message size of 0 and a priority of 2.
With these changes, the program should read the file in 4096-byte chunks, send each chunk through the message queue, and then send an empty message to the receiver when it reaches the end of the file.

#include <fcntl.h>
#include <mqueue.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#define QUEUE_NAME "/cpsc351messagequeue"
#define MAX_MESSAGE_SIZE 4096
#define MAX_QUEUE_SIZE 8192
int main(int argc, char *argv[]) {
if (argc < 2) {
fprintf(stderr, "Usage: %s <file-name>\n", argv[0]);
return 1;
}
// Open the message queue
mqd_t queue = mq_open(QUEUE_NAME, O_WRONLY);
if (queue == (mqd_t)-1) {
perror("Error opening message queue");
return 1;
}
// Open the file
FILE *file = fopen(argv[1], "r");
if (file == NULL) {
perror("Error opening file");
return 1;
}
// Read at most 4096 bytes from the file and send them through the message queue
char buffer[MAX_MESSAGE_SIZE];
size_t bytes_read;
while ((bytes_read = fread(buffer, 1, MAX_MESSAGE_SIZE, file)) > 0) {
if (mq_send(queue, buffer, bytes_read, 1) == -1) {
perror("Error sending message");
return 1;
}
}
// Send an empty message to the receiver with a priority of 2 to indicate that the sending is done
if (mq_send(queue, "", 0, 2) == -1) {
perror("Error sending message");
return 1;
}
// Close the file and message queue
fclose(file);
mq_close(queue);
return 0;
}

Related

Error while trying to send a message with FIFO

I'm new to this kind of programming so i'm sorry in advance if it's a dump question.I'm trying to do a very simple task but i don't seem to get what goes wrong.
I have a parent process that creates a number of children processes, and with the usage of FIFOs i want to send a message to all of the children (e.g "hi"), the message get's received by the processes but there is an error coming up no matter what i do and can't seem to find what's wrong.
Here is the parent's main function:
int main(int argc, char *argv[])
{
int num_monitors, buf_size; //command line arguments
num_monitors = stoi(argv[1]);
buf_size = stoi(argv[2]);
// Structures to store monitor info
Monitors *m_info = new Monitors[num_monitors]; // Stores monitor pid & pipe ends
create_n_monitors(m_info,num_monitors,buf_size,input_dir_path);
sleep(1); // making sure all pipes get created
for(int i=0; i<num_monitors; i++) // opening the write end now that the monitors have been created
{
m_info[i].write_fd = open(m_info[i].write_p, O_WRONLY | O_NONBLOCK);
if (m_info[i].write_fd == -1){perror("open # 27 main parent");exit(1);}
}
for(int i=0; i<num_monitors; i++)
send_message(m_info[i].write_fd, (char*)"hi", buf_size);
delete [] m_info;
return 0;
}
Here's the class where i keep every process information stored:
class Monitors
{
public:
pid_t m_pid; // monitors's PID
char read_p[32]; // write monitor - read parent pipe name
char write_p[32]; // read monitor - write parent pipe name
int read_fd; // file descriptor for read fifo of monitor
int write_fd; // file descriptor for write fifo of monitor
Monitors();
~Monitors();
};
Here's how i create the processes and the pipes(FIFOs):
void create_n_monitors(Monitors *m_info, int num_monitors, int buf_size, char *input_dir)
{
create_unique_fifo(true, NULL, 0); // creates a fifo file
for (int i = 0; i < num_monitors; ++i) // create num monitors
create_monitor(m_info, i, buf_size, input_dir);
}
/* ========================================================================= */
// Create a monitor and it's named fifos. Store it's info in <m_info[index]>.
void create_monitor(Monitors *m_info, int index, int buf_size, char *input_dir)
{
create_unique_fifo(false, m_info, index); // Create fifos
pid_t pid = fork();
if(pid == -1) {
perror("fork");
exit(1);
}
else if ( pid == 0) { // we are in the child monitor, read_p(read parent) : monitor's write end of the fifo
// write_p(write parent): monitor's read end
char buf_size_str[15];
sprintf(buf_size_str, "%d", buf_size); // buf_size must be a char*
execl("./Monitor","Monitor", buf_size_str, m_info[index].read_p, m_info[index].write_p, (char * )NULL);
perror("execl");
exit(1);
}
//else
m_info[index].m_pid = pid; // Store it's pid
}
/* ========================================================================= */
// If <setup> is true, create a directory to store fifos.
void create_unique_fifo(bool setup, Monitors *m_info, int index)
{
static char fifo_name[32];
static int counter = 0;
if (setup == true)
{
char dir_path[] = "named_fifos";
if (access(dir_path, F_OK) == 0) // If dir already exists (due to abnormal previous termination, eg: SIGKILL)
delete_flat_dir(dir_path); // completely remove it
if (mkdir(dir_path, 0777) == -1){perror("mkdir # unique_fifo");exit(1);}
sprintf(fifo_name, "named_fifos/f");
return;
}
struct stat stat_temp;
// Create a unique name (e.g named_fifos1R , named_fifos6W )
sprintf(m_info[index].read_p, "%s%d%c", fifo_name, counter, 'R');
// Create fifos
if(stat(m_info[index].read_p, &stat_temp) == -1){
if (mkfifo(m_info[index].read_p,0666) < 0 ){perror("mkfifo # unique_fifo");exit(1);}
}
m_info[index].read_fd = open(m_info[index].read_p, O_RDONLY | O_NONBLOCK);
if (m_info[index].read_fd == -1) {perror("open # 73 setup_monitors");exit(1);}
sprintf(m_info[index].write_p, "%s%d%c", fifo_name, counter, 'W');
++counter; // counter used for pipe names
}
/* ========================================================================= */
// Remove a flat directory and its contents.
void delete_flat_dir(char *init_flat_path)
{
char flat_path[32];
strcpy(flat_path, init_flat_path);
DIR *dir = opendir(flat_path);
if (dir == NULL){perror("opendir # delete_flat_dir"); exit(1);}
struct dirent *entry;
while ((entry = readdir(dir)) != NULL) // Delete contents/files
{
char *f_name = entry->d_name;
if (!strcmp(f_name, ".") || !strcmp(f_name, ".."))
continue;
char f_path[32];
snprintf(f_path, 32, "%s/%s", flat_path, f_name); // Remove file
if (remove(f_path) == -1){perror("remove # delete_flat_dir"); exit(1);}
}
// Remove dir
if (closedir(dir) == -1){perror("closedir 2 # delete_flat_dir"); exit(1);}
if (rmdir(flat_path) == -1){perror("rmdir # delete_flat_dir"); exit(1);}
}
Here are the functions used for the communication of the processes and parent:
// Sends <message> to file descriptor <fd>
void send_message(int fd, char *message, int buf_size)
{
int length = strlen(message);
char buffer[10];
sprintf(buffer, "%d#", length);
write(fd, buffer, 9); // sending the number of bytes reader is about to read
write(fd, message, length); // sending the message itself
}
char *read_message(int read_end_fd, int buf_size)
{
char buffer[10];
int fifo_buffer_size = buf_size;
read(read_end_fd, buffer, 9);
char * tok = strtok(buffer, "#");
int length = atoi(tok); // how many characters will be received
char * input_read = new char[length + 1];
char * str = input_read;
int bytes_read = 0, total_bytes = 0; // We might need to read less or more bytes
fifo_buffer_size = length < fifo_buffer_size ? length : fifo_buffer_size; // // than <buf_size>
while(total_bytes < length)
{
str += bytes_read; // move str pointer
bytes_read = read(read_end_fd, str, fifo_buffer_size); //and read the next <buf_size> characters
total_bytes += bytes_read; // adding them to the total amount of bytes read altogether
if((total_bytes + fifo_buffer_size) > length)
fifo_buffer_size = length - total_bytes; // reading exactly the amount that's left
}
input_read[length] = '\0';
return input_read;
}
And lastly the processes main function:
int create_unique_fifo(char* read_fifo)
{
int read_fd;
struct stat stat_temp;
// Create fifos
if(stat(read_fifo, &stat_temp) == -1){
if (mkfifo(read_fifo,0666) < 0 ){perror("mkfifo # unique_fifo 37");exit(1);}
}
read_fd = open(read_fifo, O_RDONLY); // Open named pipe for reading
if (read_fd == -1){perror("open # monitor.cpp 1"); exit(1);}
return read_fd;
}
int main(int argc, char* argv[])
{
int buf_size = stoi(argv[1]); // Process command line args
char read_fifo[100], write_fifo[100];
strcpy(write_fifo, argv[2]); // parent read - monitor write
strcpy(read_fifo, argv[3]); // parent write - monitor read
int read_fd, write_fd;
read_fd = create_unique_fifo(read_fifo);
write_fd = open(write_fifo, O_WRONLY | O_NONBLOCK); // Open named pipe for writing
if (write_fd == -1){perror("open # monitor.cpp 2"); exit(1);}
char* message;
message = read_message(read_fd, buf_size);
cout << "2:" << message << endl;
return 0;
}
I'm using the valgrind debugger and get the following result when num_monitors=5 and buf_size=2:
==29783== Syscall param write(buf) points to uninitialised byte(s)
==29783== at 0x4B691E7: write (write.c:26)
==29783== by 0x10B85B: send_message(int, char*, int) (in /home/sofia/Desktop/syspro-2/travelMonitor)
==29783== by 0x10A80F: main (in /home/sofia/Desktop/syspro-2/travelMonitor)
==29783== Address 0x1ffefffc81 is on thread 1's stack
==29783== in frame #1, created by send_message(int, char*, int) (???:)
==29783==
2:hi
2:hi
2:hi
2:hi
2:hi
==29783==
==29783== HEAP SUMMARY:
==29783== in use at exit: 0 bytes in 0 blocks
==29783== total heap usage: 4 allocs, 4 frees, 138,864 bytes allocated
==29783==
==29783== All heap blocks were freed -- no leaks are possible
==29783==
==29783== Use --track-origins=yes to see where uninitialised values come from
==29783== For lists of detected and suppressed errors, rerun with: -s
==29783== ERROR SUMMARY: 5 errors from 1 contexts (suppressed: 0 from 0)
Any idea why this could be happening? I added sleep(1) after the creation of the processes to make sure all the fifos get created in time but still get this error... Any help would be much appreciated
In send_message, you always write 9 bytes from buffer, but not all of those bytes have had a value written to them. This is because the sprintf that populates buffer only writes to the first few locations, possibly as few as 3.
The solution is to either initialize them all to 0
char buffer[10] = 0;
or only write the number of bytes that are in the string. This is easily known from the value returned by sprintf.
auto buf_len = sprintf(buffer, "%d#", length);
write(fd, buffer, buf_len);

Why does read() block indefinitely when reading a buffer

I'm new to socket programming and wanted to try something simple. This program can manipulate settings on my tv. All messages are 24 bytes. There may be one or more messages returned. I cannot figure out a good solution to get all of the messages without read() blocking on me.
What is below would be what I hoped to be a simple solution. It seems to work in a lot of example code I have found. However, what happens is after the first loop it seems to just block on the read() operation infinitely. If I remove the loop and just put multiple reads, the same thing happens. As long as I don't try to read more information that is sent, I'm ok.
I did try a couple of other things like turning off blocking, and adding a timer. neither worked. At this point I can live with a couple seconds of blocking. I just want the program to exit normally after the read.
adding output for a power_on command. It correctly outputs the two lines it should then blocks indefinitely.
Dans-MBP:~ mreff555$ ./tvthing
24: *SAPOWR0000000000000000
24: *SNPOWR0000000000000001
code below:
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <cstdio>
#include <cstdlib>
#include <unistd.h>
#include <cstring>
#include <sys/time.h>
#define PORT 20060
#define POWER_ON "*SCPOWR0000000000000001\n"
#define POWER_OFF "*SCPOWR0000000000000000\n"
#define POWER_STATUS "*SEPOWR################\n"
#define POWER_TOGGLE "*STPOWR################\n"
int main(int argc, char const * argv[])
{
struct sockaddr_in tvAddress;
struct hostent *host = gethostbyname("192.168.1.128");
memset(&tvAddress, 0, sizeof(tvAddress));
tvAddress.sin_family = AF_INET;
tvAddress.sin_addr.s_addr = htonl(INADDR_ANY);
tvAddress.sin_addr.s_addr = ((struct in_addr*)(host->h_addr))->s_addr;
tvAddress.sin_port = htons(PORT);
char sendBuffer[24] = {0};
char recBuffer[24] = {0};
int socket_fd;
if((socket_fd = socket(AF_INET,SOCK_STREAM, 0)) < 0)
{
perror("socket failed");
exit(EXIT_FAILURE);
}
else
{
if(connect(socket_fd, (struct sockaddr *)&tvAddress, sizeof(struct sockaddr)))
{
perror("connection failed failed");
exit(EXIT_FAILURE);
}
memcpy(&sendBuffer, &POWER_STATUS, sizeof(sendBuffer));
write(socket_fd, sendBuffer, strlen(sendBuffer));
int ret;
while((ret = read(socket_fd, recBuffer, sizeof(recBuffer)) > 0))
{
printf("%d: %s\n", ret, recBuffer);
}
close(socket_fd);
}
}
You need to read until your buffer is full like this:
unsigned readLen = 0;
unsigned totalLen = sizeof(recBuffer);
while (readLen < totalLen) {
int ret = read(socket_fd, recBuffer + readLen, totalLen - readLen);
if (ret > 0) {
readLen += ret;
} else {
// error handling here
break;
}
}
This is needed because read() returns only the currently available amount of bytes which might be less than you have requested. From the corresponding man-page:
RETURN VALUE
On success, the number of bytes read is returned (zero indicates end of file), and the file position is advanced by this number. It is not an error if this number is smaller than the number of bytes requested; this may happen for example because fewer bytes are actually available right now (maybe because we were close to end-of-file, or because we are reading from a pipe, or from a terminal), or because read() was interrupted by a signal.
If you need to receive several responses you can put the described algorithm into a function and use it repeatedly. In any case you need to know how many responses to expect otherwise your read() will block because it seems that your TV's server is programmed to keep the connection open and it is client's responsibility to choose when to disconnect.
If you decide to make your application more sophisticated you can use one of the IO Multiplexing mechanisms to make your wait for response interruptable by timer or terminal input. For example:
while (true) {
pollfd fds[] = {
{ socket_fd, POLLIN, 0 },
{ STDIN_FILENO, POLLIN, 0 }
};
int ret = poll(fds, sizeof(fds) / sizeof(*fds), -1);
if (ret > 0) {
if (fds[0].revents & POLLIN) {
readResponse(); // read and process response
}
if (fds[1].revents & POLLIN) {
break; // exit on terminal input
}
}
}
As it turns out, select is designed exactly for that purpose. It checks the specified file descriptors for a specified time interval, and if successful repeats the process. Tweaking the time interval minimizes the blocking while allowing enough time for additional messages to come in.
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <cstdio>
#include <cstdlib>
#include <unistd.h>
#include <cstring>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/select.h>
#define PORT 20060
#define POWER_ON "*SCPOWR0000000000000001\n"
#define POWER_OFF "*SCPOWR0000000000000000\n"
#define POWER_STATUS "*SEPOWR################\n"
#define POWER_TOGGLE "*STPOWR################\n"
int main(int argc, char const * argv[])
{
struct sockaddr_in tvAddress;
struct hostent *host = gethostbyname("192.168.1.128");
memset(&tvAddress, 0, sizeof(tvAddress));
tvAddress.sin_family = AF_INET;
tvAddress.sin_addr.s_addr = htonl(INADDR_ANY);
tvAddress.sin_addr.s_addr = ((struct in_addr*)(host->h_addr))->s_addr;
tvAddress.sin_port = htons(PORT);
char sendBuffer[24] = {0};
char recBuffer[24] = {0};
int socket_fd;
if((socket_fd = socket(AF_INET,SOCK_STREAM, 0)) < 0)
{
perror("socket failed");
exit(EXIT_FAILURE);
}
else
{
if(connect(socket_fd, (struct sockaddr *)&tvAddress, sizeof(struct sockaddr)))
{
perror("connection failed failed");
exit(EXIT_FAILURE);
}
struct timeval tv;
fd_set sockRead;
int selectStatus;
memcpy(&sendBuffer, &POWER_ON, sizeof(sendBuffer));
write(socket_fd, sendBuffer, strlen(sendBuffer));
do
{
FD_ZERO(&sockRead);
FD_SET(socket_fd, &sockRead);
tv.tv_sec = 2;
tv.tv_usec = 500000;
selectStatus = select(socket_fd + 1, &sockRead, NULL, NULL, &tv);
switch(selectStatus)
{
case -1:
perror("select()");
exit(EXIT_FAILURE);
break;
case 0:
break;
default:
printf("Ready for Reading\n");
read(socket_fd, recBuffer, sizeof(recBuffer));
printf("%s\n", recBuffer);
}
}while (selectStatus > 0);
close(socket_fd);
}
}

Unable to send data using pipe to second app which I launched via exec (C++)

I have to pass some data from one application to another. I am using pipe for the same. My first application first writes to pipe and then execs second application. But while reading from pipe, it returns nothing.
I am forking a child process, in which I am passing some data using fd[1]. And later I am calling another app using exec.
The code to read data using fd[0] is in the second app. But I am not getting anything.
appLaunch.cpp
int main()
{
/*
This application will send parameters to another application
*/
int fd[2];
pid_t childpid;
char string[] = "Hello, world!\n";
pipe(fd);
if((childpid = fork()) == -1)
{
perror("fork");
exit(1);
}
if(childpid == 0)
{
/* Child process closes up input side of pipe */
close(fd[0]);
/* Send "string" through the output side of pipe */
write(fd[1],string,(strlen(string)+1));
printf("Starting app...\n");
execlp("/home/varun/Documents/c programs/C-IPC/app","/home/varun/Documents/c programs/C-IPC/app",NULL);
exit(0);
}
else
{
}
return(0);
}
app.cpp
int main(int argc, char *argv[])
{
/*
This application will read parameters from
calling process from file descriptors
*/
int fd[2],nbytes;
pipe(fd);
close(fd[1]);
char readbuffer[80];
/* Read in a string from the pipe */
nbytes = read(fd[0],readbuffer, sizeof(readbuffer));
printf("\nReceived string: %s", readbuffer);
}
Well, I got the solution.
I had to open a read pipe in child process of (process that calls another app) appLaunch.cpp and write pipe in parent process of appLaunch.cpp. And read it via STDOUT in another application i.e. app.cpp.
Here is solution code:
app.cpp
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <string.h>
int main(int argc, char *argv[])
{
/*
This application will read parameters from
calling process from file descriptors
*/
int nbytes;
printf("\n %s",argv[0]);
char readbuffer[80];
/* Read in a string from the pipe */
nbytes = read(0,readbuffer, sizeof(readbuffer));
printf("\nReceived string: %s", readbuffer);
argv[1] = readbuffer;
}
appLaunch.cpp
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <string.h>
int main()
{
/*
This application will send parameters to another application
*/
// printf("App Launcher is now live!\n");
int fd[2], nbytes;
pid_t childpid;
char string[] = "Hello, world!\n";
pipe(fd);
if((childpid = fork()) == -1)
{
perror("fork");
exit(1);
}
if(childpid == 0)
{
/* Child process closes up input side of pipe */
close(fd[1]);
dup2(fd[0],STDIN_FILENO);
printf("Starting app...\n");
execlp("/home/varun/Documents/c programs/C-IPC/app","/home/varun/Documents/c programs/C-IPC/app",NULL);
exit(0);
}
else
{
close(fd[0]);
dup2(fd[1],STDOUT_FILENO);
write(fd[1],string,(strlen(string)+1));
}
return(0);
}

How to deactivate input statement after some time?

We know input function or operator (cin, scanf,gets….etc) wait to take input form user & this time has no limit.
Now, I will ask a question & user give the answer, till now there no problem but my problem is “user has a time(may 30 or 40 sec) to give the input, if he fail then input statement will automatically deactivated & execute next statement.”
I think you get my problem. Then please help me in this situation. It will be better if someone give me some really working example code.
I use codebolck 12.11 in windows 7.
An approach for *IX'ish systems (including Cygwin on windows):
You could use alarm() to schedule a SIGALRM, then use read(fileno(stdin), ...).
When the signal arrives read() shall return with -1 and had set errno to EINTR.
Example:
#define _POSIX_SOURCE 1
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>
void handler_SIGALRM(int signo)
{
signo = 0; /* Get rid of warning "unused parameter ‘signo’" (in a portable way). */
/* Do nothing. */
}
int main()
{
/* Override SIGALRM's default handler, as the default handler might end the program. */
{
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
sa.sa_handler = handler_SIGALRM;
if (-1 == sigaction(SIGALRM, &sa, NULL ))
{
perror("sigaction() failed");
exit(EXIT_FAILURE);
}
}
alarm(2); /* Set alarm to occur in two seconds. */
{
char buffer[16] = { 0 };
int result = read(fileno(stdin), buffer, sizeof(buffer) - 1);
if (-1 == result)
{
if (EINTR != errno)
{
perror("read() failed");
exit(EXIT_FAILURE);
}
printf("Game over!\n");
}
else
{
alarm(0); /* Switch of alarm. */
printf("You entered '%s'\n", buffer);
}
}
return EXIT_SUCCESS;
}
Note: In the example above the blocking call to read() would be interupted on any signal arriving. The code to avoid this is left as an execise to the reader ... :-)
Another Method:
You can use POSIX select() function (and some macros FD_ZERO, FD_SET, FD_ISSET) to check which file descriptors (descriptor number 0 i.e. stdin, in this case) are ready to be read in a given time interval. When they are ready, use appropriate function to read the data (scanf() in this case).
This code might help you understand, what I want to say:
#include <sys/select.h>
#include <sys/time.h>
#include <stdio.h>
#define STDIN 0 // Standard Input File Descriptor
int main()
{
fd_set input; // declare a "file descriptor set" to hold all file descriptors you want to check
int fds, ret_val, num; // fds: Number of file descriptors;
struct timeval tv; // structure to store Timeout value in the format used by select() function
unsigned int timeout = 5; // Your timeout period in seconds
tv.tv_sec = timeout;
tv.tv_usec = 0;
fds = STDIN + 1; // Set number of file decriptors to "1 more than the greatest file descriptor"
// Here, we are using only stdin which is equal to 0
FD_ZERO(&input); // Initialize the set with 0
FD_SET(STDIN, &input); // Add STDIN to set
printf("Enter a number within %d secs\n", timeout);
ret_val = select(fds, &input, NULL, NULL, &tv);
// We need to call select only for monitoring the "input file descriptor set"
// Pass rest of them as NULL
if (ret_val == -1) // Some error occured
perror("select()");
else if (ret_val > 0) // At least one of the file descriptor is ready to be read
{
// printf("Data is available now.\n");
if(FD_ISSET(0, &input)) // Check if stdin is set, here its not necessary as we are using STDIN only
// So ret_val>0 means STDIN is raedy to read
{
scanf("%d", &num);
}
}
else
printf("No data within five seconds.\n"); // select returns zero on timeout
return 0;
}
More Help:
select(2)
You can also try using poll() function available in (again a POSIX standard function) as an alternative to select(). See poll() & poll(2)
#include <cstddef>
#include <ctime>
#include <iostream>
#include <conio.h>
bool get_input ( char *buffer, std::size_t size, int timeout )
{
std::time_t start = std::time ( 0 );
std::size_t n = 0;
for ( ; ; ) {
if ( n == 0 && std::difftime ( std::time ( 0 ), start ) >= timeout )
return false;
if ( kbhit() ) {
if ( n == size - 1 )
break;
char ch = (int)getche();
if ( ch == '\r' ) {
buffer[n++] = '\n';
break;
}
else
buffer[n++] = ch;
}
}
buffer[n] = '\0';
return true;
}
int main()
{
char buffer[512] = {0};
if ( !get_input ( buffer, 512, 5 ) ) {
std::cout<<"Input timed out\n";
buffer[0] = '\n';
}
std::cout<<"input: \""<< buffer <<"\"\n";
}

Program quits if pipe is closed

I am trying to write to a pipe using C++. The following code gets called in an extra thread:
void writeToPipe()
{
int outfifo;
char buf[100];
char outfile[] = "out";
mknod(outfile, S_IFIFO | 0666, 0);
if ((outfifo = open(outfile, O_WRONLY)) < 0) {
perror("Opening output fifo failed");
return false;
}
int currentTimestamp = (int)time(0);
int bufLen = sprintf(bug, "Time is %d.", currentTimestamp);
write(outfifo, buf, bufLen);
}
The thread is called in main using:
thread writeThread(writeToPipe);
writeThread.detach();
If the pipe is not opened by another process, the C++ program just quits without an error. I don't know how to check if the pipe is opened.