How do I get a stream to continue after write () has written fewer bytes than requested?
I am using the following code to write data over a named pipe from one application to another. The thread on which the write occurs should never exit. But if r_write () returns less than necessary, the thread / program stops for some reason. How can I make the stream continue as soon as the entry returns less than needed?
ssize_t r_write(int fd, char *buf, size_t size)
{
char *bufp;
size_t bytestowrite;
ssize_t byteswritten;
size_t totalbytes;
for (bufp = buf, bytestowrite = size, totalbytes = 0;
bytestowrite > 0;
bufp += byteswritten, bytestowrite -= byteswritten) {
byteswritten = write(fd, bufp, bytestowrite);
if ((byteswritten) == -1 && (errno != EINTR))
return -1;
if (byteswritten == -1)
byteswritten = 0;
totalbytes += byteswritten;
}
return totalbytes;
}
void* sendData(void *thread_arg)
{
int fd, ret_val, count, numread;
string word;
char bufpipe[5];
ret_val = mkfifo(pipe, 0777); //make the sprout pipe
if (( ret_val == -1) && (errno != EEXIST))
{
perror("Error creating named pipe");
exit(1);
}
while(1)
{
if(!sproutFeed.empty())
{
string s;
s.clear();
s = sproutFeed.front();
int sizeOfData = s.length();
snprintf(bufpipe, 5, "%04d", sizeOfData);
char stringToSend[strlen(bufpipe) + sizeOfData +1];
bzero(stringToSend, sizeof(stringToSend));
strncpy(stringToSend,bufpipe, strlen(bufpipe));
strncat(stringToSend,s.c_str(),strlen(s.c_str()));
strncat(stringToSend, "\0", strlen("\0"));
int fullSize = strlen(stringToSend);
cout << "sending string" << stringToSend << endl;
fd = open(pipe,O_WRONLY);
int numWrite = r_write(fd, stringToSend, strlen(stringToSend) );
if(numWrite != fullSize)
{
bzero(bufpipe, strlen(bufpipe));
bzero(stringToSend, strlen(stringToSend));
cout << "NOT FULL SIZE WRITE " << endl; //program ends here??
}
else
{
sproutFeed.pop();
bzero(bufpipe, strlen(bufpipe));
bzero(stringToSend, strlen(stringToSend));
}
}
else
{
sleep(1);
}
}
}
a source to share
FIFO write error. Examine the meaning errno
to find out why. Look errno.h
on your system to decipher the errno value. If the program ends while trying to write to the console, the cause may be related.
Also, your loop does not close the file descriptor for the FIFO ( close(fd)
).
Finally, you mentioned multithreading. The standard library stream cout
on your system may not (and probably not) is thread safe. In this case, writing to the console simultaneously from multiple streams will lead to unpredictable errors.
a source to share
If it write()
returns a positive (non-zero, non-negative) value for the number of bytes written, it was successful, but there was no room for all the data. Try again with the remainder of the data in the buffer (and try again if necessary). Don't forget that FIFOs have limited capacity - and writers will be detained if necessary.
If the value write()
returns a negative value, the write fails. You most likely won't be able to recover, but check errno
for this reason.
I think the only circumstance that write()
can return zero is if you have a file descriptor with O_NONBLOCK
and the write attempt is blocked. You may need to review the man page write()
to check any other possibilities.
What your stream does depends on why it survived the short recording and what you want to do.
a source to share
You need to make the file descriptor non-blocking. You can do it like this:
fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);
Explanation
This is how it works fcntl
(not complete description - look at man fcntl
). First of all, it includes:
#include <unistd.h>
#include <fcntl.h>
reading file descriptor flags
Use F_GETFL
to get the flags of the file descriptor. From man fcntl
:
F_GETFL
Read the file descriptor flags.
RETURN VALUE
For a successful call, the return value depends on the operation:
F_GETFL Value of flags.
and this is how it is used:
int fd_flags = fcntl(fd, F_GETFL);
write file descriptor flags
Use F_SETFL
to set a flag O_NONBLOCK
. Again, quoting from man fcntl
:
F_SETFL
Set the file status flags part of the descriptor flags to the
value specified by arg. Remaining bits (access mode, file cre?
ation flags) in arg are ignored. On Linux this command can
only change the O_APPEND, O_NONBLOCK, O_ASYNC, and O_DIRECT
flags.
and this is how it is used:
fcntl(fd, F_SETFL, fd_flags | O_NONBLOCK);
a source to share