According to Linux Programmer's Manual, poll can wait for one of a set of file descriptors to become ready to perform I/O.
According to my understanding, if I add POLLIN to events, poll will return with a > 0 integer, when there is at least one fd which is ready to be read.
Consider the following code, In this code, I want the program echos my input immediately after I typed the character \n.
int main(){
char buffer[maxn];
while (true) {
struct pollfd pfd[1];
std::memset(pfd, 0, sizeof pfd);
pfd[0].fd = STDIN_FILENO;
pfd[0].events = POLLIN;
int ret = poll(pfd, 1, 1000);
if (ret < 0) {
}
else if (ret == 0) {
}
else {
if ((pfd[0].revents & POLLIN) == POLLIN) {
int n;
n = fscanf(stdin, "%s", &buffer);
if(n > 0){
printf("data from stdin: %s\n", buffer);
}
}else if((pfd[1].revents & POLLHUP) == POLLHUP){
break;
}
}
}
}
When I type
aa bb cc dd
I thought fscanf hasn't retrieved all data from stdin, because it only reads aa. So when the loop restarts, stdin's fd should still be ready. As a consequence, (pfd[0].revents & POLLIN) == POLLIN still stands, so I thought we can see the following output
data from stdin: aa
data from stdin: bb
data from stdin: cc
data from stdin: dd
However, actually only the first line is printed. I got strange here, I think this is similar with epoll's Edge-triggered mode. However, poll is level-triggered.
So can you explain why this happens with fscanf?
Polling works at the file descriptor level while fscanf works at the higher file handle level.
At the higher level, the C runtime library is free to cache the input stream in such a way that it would affect what you can see at the lower level.
For example (and this is probably what's happening here), the first time you fscanf your word aa, the entire line is read from the file descriptor and cached, before that first word is handed back to you.
A subsequent fscanf (with no intervening poll) would first check the cache to get the next word and, if it weren't there, it would go back to the file descriptor to get more input.
Unfortunately, the fact that you're checking for a poll event before doing this is causing problems. As far as the file descriptor level goes, the entire line has been read by your first fscanf so no further input is available - poll will therefore wait until such information does become available.
You can see this in action if you change:
n = fscanf(stdin, "%s", buffer);
into:
n = read(STDIN_FILENO, buffer, 3);
and change the printf to:
printf("data from stdin: %*.*s\n", n, n, buffer);
In that case, you do get the output you expect as soon as you press the ENTER key:
data from stdin: aa
data from stdin: bb
data from stdin: cc
data from stdin: dd
Just keep in mind that sample code is reading up to three characters (like aa<space>) rather than a word. It's more to illustrate what the problem is rather than give you the solution (to match your question "Can you explain why this happens?").
The solution is not to mix descriptor and handle based I/O when the caching of the latter can affect the former.
Related
I have this function that takes a SOCKET and a file name to the output file, then it tries to receive and output the data to a file, when compiling and running the code it works fine but the program does not exit and the output file (file.txt) contains some unreadable garbage text
the rest of the code work fine and tested, I am sure the problem is in this file but can't tell what and where
int recv_file(SOCKET soc, const char * fname)
{
FILE * ptr;
char buffer[MAX];
unsigned long long int x = 0;
if (fopen_s(&ptr, fname , "wb") != 0)
{
printf("Failed to receive file \n");
return 1;
}
do
{
c = recv(soc, buffer, MAX, 0);
printf("recv count : %d\n",c);
// here was -> fwrite(buffer, 1, sizeof(buffer), ptr);
fwrite(buffer, 1, c, ptr);
}
while ( c > 0);
printf("Total received : %lld\n", x);
fclose(ptr);
return 0;
}
as an output it prints only one line recv count : 65
I tried to use closesocket(soc);WSACleanup(); but this does not solve the problem
for the server, I tested with netcat and python socketserver and had same behavior for both
also the last printf right after the do-while does not get printed to the screen
Data from network can come in chuncks
recv returns negative value on errors that what break handles (stops loop).
recv returns number of bytes received.
fwrite should write number of bytes equal to those which has been received, so it should be:
fwrite(buffer, 1, c, ptr);
Passing there sizeof(buff) will record trash in a file (content form previous read or memory trash).
Now question is what sender does when there is no data. If nothing recv will block waiting for new data. If sender closes tcp connection then respective error should be reported by recv and loop should be ended.
If you are fetching data form some HTTP server then most probably server assumes that client will close connection. Server just waits for next request.
Note also that depending on SOCKET configuration recv can be blocking or not. So depending on that recv may return 0 on success when in fact there will be new data in future.
I'm trying to establish an inter process communication on Linux using named pipes. At first glance my code seems to work, but I noticed that sometimes data written to the pipe by the "main" process is read twice by the "child" process (in fact it's two separate programs).
Program 1 (write only, starts first) is a legacy program. The below code is implemented in a onclick-function for a button on a GUI. When I press the button the data string shall be sent via pipe to another program. Code:
main.h
const char * FSCpipe = "/tmp/fscpipe";
int counter = 1;
main()
::mkfifo(FSCpipe, 0666);
OnClick-Function
QString data = "179.45";
int fd;
char msg[10];
fd = ::open(FSCpipe, O_WRONLY | O_NONBLOCK);
for(int i = 0; i < data.length(); i++) {
msg[i] = data.at(i).toLatin1();
}
msg[data.length()] = '\0';
::write(fd, msg, strlen(msg)+1);
::close(fd);
qDebug() << QString("Counter: %1").arg(counter);
counter++;
Program 2 (only read, starts second) is started in a new terminal. Code:
int main(int argc, char **argv)
{
int fd;
const char * FSCpipe = "/tmp/fscpipe";
char data[10];
size_t nbytes;
nbytes = sizeof(data);
while(1) {
fd = open(FSCpipe, O_RDONLY);
ssize_t bytesread = read(fd, data, nbytes);
printf("received: %s\n", data);
close(fd);
printf("Counter: %d ", counter);
printf("chars: %d\n", bytesread);
counter++;
}
return(0);
}
Sometimes I noticed a strange behaviour, feeling like there is more data read then written. So I implemented independent counter in both programs. When I press the button in program 1, the data is send via the pipe and the counter increments. When program 2 receives and outputs the data in the terminal, its counter is also incremented. After some clicks on the button in program 1, I can see a higher counter value in program 2, indicating that it reads more often then program 1 writes. Why is that ?
Apart from that, the data string should contain special characters encoded in UTF-8, like this:
QString data = "197,45 \xc2\xb5m";
How should I convert the string to send it correctly via pipe?
Thank you for helping me!
I found some helpful information here, stating:
"If all file descriptors referring to the write end of a pipe have been closed, then an attempt to read(2) from the pipe will see end-of-file (read(2) will return 0)"
I took out fd = ::open(...); and ::close(fd); from my onclick-function in program 1 and put them into the mainwindow-constructor and the mainwindow-close-function respectively. So the write end is always opened and program 2 works as intended.
Thank you all for your help.
I'm trying to receive a number from an Arduino as an integer in C++. The full code is below:
#define STRICT
#include <tchar.h>
#include <windows.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "Serial.h"
#include <boost\lexical_cast.hpp>
enum { EOF_Char = 27 };
int __cdecl _tmain(int /*argc*/, char** /*argv*/)
{
CSerial serial;
LONG lLastError = ERROR_SUCCESS;
// Attempt to open the serial port (COM4)
lLastError = serial.Open(_T("COM4"), 0, 0, false);
// Setup the serial port (9600,8N1, which is the default setting)
lLastError = serial.Setup(CSerial::EBaud9600, CSerial::EData8, CSerial::EParNone, CSerial::EStop1);
// Register only for the receive event
lLastError = serial.SetMask(CSerial::EEventBreak |
CSerial::EEventCTS |
CSerial::EEventDSR |
CSerial::EEventError |
CSerial::EEventRing |
CSerial::EEventRLSD |
CSerial::EEventRecv);
// Use 'non-blocking' reads, because we don't know how many bytes
// will be received. This is normally the most convenient mode
// (and also the default mode for reading data).
lLastError = serial.SetupReadTimeouts(CSerial::EReadTimeoutNonblocking);
// Keep reading data, until an EOF (CTRL-Z) has been received
bool fContinue = true;
do
{
// Wait for an event
lLastError = serial.WaitEvent();
// Save event
const CSerial::EEvent eEvent = serial.GetEventType();
// Handle data receive event
if (eEvent & CSerial::EEventRecv)
{
// Read data, until there is nothing left
DWORD dwBytesRead = 0;
char szBuffer[101];
do
{
// Read data from the COM-port
lLastError = serial.Read(szBuffer, sizeof(szBuffer) - 1, &dwBytesRead);
if (dwBytesRead > 0)
{
// Finalize the data, so it is a valid string
szBuffer[dwBytesRead] = '\0';
// Display the data
printf("%s", szBuffer);
// Check if EOF (CTRL+'[') has been specified
if (strchr(szBuffer, EOF_Char))
fContinue = false;
}
} while (dwBytesRead == sizeof(szBuffer) - 1);
}
} while (fContinue);
// Close the port again
serial.Close();
return 0;
}
I have my Arduino constantly sending out the number 51. This code works fine and consistently displays "51". However, I want an int to manipulate in C++.
First I added
std::stringstream str(szBuffer);
int tester;
str >> tester;
printf("My number is: %d\n", tester+1);
right after
printf("%s", szBuffer);
A typical result looks like:
51My number is: 52
51My number is: 52
51My number is: 52
51My number is: 52
51My number is: 52
5My number is: 6
1My number is: 2
After doing it perfectly 5 or 6 times, the output always separates the incoming digits once or twice in a row (I haven't been able to find a specific pattern yet, but it's always 5-6 and 1-2).
My other attempt was to use the boost library:
int tester = boost::lexical_cast<int>(szBuffer);
printf("My number is: %d\n", tester);
right after
printf("%s", szBuffer);
and I get the same result (1-2 errors after 5-6 correct ones). I don't think the Arduino is sending bad data, since just a
printf("%s", szBuffer);
will never deviate from the number it's supposed to be. Could the conversion be messing up the receiving of data? Thanks.
EDIT: The Arduino code is:
void setup() {
Serial.begin(9600); // same as in your c++ script
}
void loop() {
Serial.print(51);
delay(1000);
}
With serial ports, there is no mechanism where a transmitter can inform a receiver how many bytes were transmitted as a block. I.e. there's no "hidden" marker where Serial.print(51); tells the receiver that it sent two characters as one number. You have to add some kind of indication (spaces, commas, line ends, initial byte counts, whatever) to your serial protocol.
Because of this, the number of characters you get from serial.Read depends on the number of characters you asked it to read (the second parameter) and how many characters are in the serial port's receive buffer, whichever is smaller. Most of the time, it seems the Arduino sends both digits before you call serial.Read, but sometimes it only gets one out in time... and the second is read the next time through the loop.
So let's assume you decided to use line ends to separate your numbers. All you have to do on the Arduino end is change to Serial.println(51);. The receive end is a little more complex.
I don't know what your serial library has in it. Most have some kind of "read line" function, and you would just replace the serial.Read call with something like:
serial.Readline(szBuffer, sizeof(szBuffer) - 1);
and it will take care of null-terminating the output. If it doesn't take care of null-termination, you'll need to find the line end and change it to a \0 yourself. From this point on, your code will work fine, because the serial.Readline function will block until it gets the whole line.
If you don't have a "read line" or at least a "read until this character" function, it's a bit harder. You have to repeatedly call serial.Read, moving through your buffer, until you see the line end character. Further, you run the risk of reading part or all of the next line, so you can't just discard all the data you read when you're done reading the number; you have to move teh data in the buffer so the next line's data (and further) is at the start of the buffer.
If you're using Boost (are you? it has no CSerial that I see), it looks like it has a read_until function. This takes three parameters: the stream you're reading from, a stream buffer to store the data in, and something to stop on. In this case, the stream buffer for storage is the one in your std::stringstream:
std::stringstream buffer;
size_t chars = boost::asio::read_until(serial, buffer.rdbuf(), '\n');
if(chars == 0) return;
int tester;
buffer >> tester;
printf("My number is: %d\n", tester+1);
I have an arduino board that is connected to a sensor. From Arduino IDE serial monitor, I see the readings are mostly 160, 150, etc. Arduino has a 10 bit ADC, so I assume the readings range from 0 to 1024.
I want to fetch that readings to my computer so that I can do further processing. It must be done this way up to this point. Now, I wrote a c++ program to read serial port buffer with Windows APIs (DCB). The transfer speed of the serial ports are set to 115200 on both the Arduino IDE and the c++ program.
I will describe my problem first: Since I want to send the readings to my computer, I expect the data looks like the following:
124
154
342
232
...
But now it looks like
321
43
5
2
123
...
As shown, the data are concatenated. I knew it because I tried to display them with [], and the data are truly messed up.
The section of the code that is doing the serial port reading on the computer is as here:
// Read
int n = 10;
char szBuff[10 + 1] = {0};
DWORD dwBytesRead = 0;
int i;
for (i = 0; i < 200; i++){
{
if(!ReadFile(hSerial, szBuff, n, &dwBytesRead, NULL)){
//error occurred. Report to user.
printf("Cannot read.\n");
}
else{
printf("%s\n" , szBuff);
}
}
}
The Arduino code that's doing the serial port sending is:
char buffer [10] = { 0 };
int analogIn = 0;
int A0_val = 0;
void setup() {
Serial.begin(115200);
}
void loop() {
A0_val = analogRead(analogIn);
sprintf(buffer, "%d", A0_val);
Serial.println(buffer);
}
I suspect that the messing up of the data is caused by different size of the buffer used to transmit and receive data in the serial port. What is the good suggestion for the size of the buffer and even better method to guarantee the successful transmission of valid data?
Thanks very much!
Your reciever code cannot assume a single read from the serial port will yield a complete line (i.e. the 2 or 3 digits followed by a '\n' that the arduino continuously sends).
It is up to the receiver to synthetize complete lines of text on reception, and only then try to use them as meaningful numbers.
Since the serial interface is extremely slow compared with your average PC computing power, there is little point in reading more than one character at a time: literally millions of CPU cycles will be spent waiting for the next character, so you really don't need to react fast to the arduino input.
Since in that particular case it will not hinder performances in the slightest, I find it more convenient to read one character at a time. That will save you the hassle of moving bits of strings around. At least it makes writing an educational example easier.
// return the next value received from the arduino as an integer
int read_arduino (HANDLE hserial)
{
char buffer[4]; // any value longer than 3 digits must come
// from a faulty transmission
// the 4th caracter is used for a terminating '\0'
size_t buf_index = 0; // storage position of received characters
for (;;)
{
char c; // read one byte at a time
if (!ReadFile(
hSerial,
&c, // 1 byte buffer
1, // of length 1
NULL, // we will read exactly one byte or die trying,
// so length checking is pointless
NULL)){
/*
* This error means something is wrong with serial port config,
* and I assume your port configuration is hard-coded,
* so the code won't work unless you modify and recompile it.
* No point in keeping the progam running, then.
*/
fprintf (stderr, "Dang! Messed up the serial port config AGAIN!");
exit(-1);
}
else // our read succeded. That's a start.
{
if (c == '\n') // we're done receiving a complete value
{
int result; // the decoded value we might return
// check for buffer overflow
if (buf_index == sizeof (buffer))
{
// warn the user and discard the input
fprintf (stderr,
"Too many characters received, input flushed\n");
}
else // valid number of characters received
{
// add a string terminator to the buffer
buffer[buf_index] = '\0';
// convert to integer
result = atoi (buffer);
if (result == 0)
{
/*
* assuming 0 is not a legit value returned by the arduino, this means the
* string contained something else than digits. It could happen in case
* of electricval problems on the line, typically if you plug/unplug the cable
* while the arduino is sending (or Mr Fluffy is busy gnawing at it).
*/
fprintf (stderr, "Wrong value received: '%s'\n", buffer);
}
else // valid value decoded
{
// at last, return the coveted value
return res; // <-- this is the only exit point
}
}
// reset buffer index to prepare receiving the next line
buf_index = 0;
}
else // character other than '\n' received
{
// store it as long as our buffer does not overflow
if (buf_index < sizeof (buffer))
{
buffer[buf_index++] = c;
/*
* if, for some reason, we receive more than the expected max number of
* characters, the input will be discarded until the next '\n' allow us
* to re-synchronize.
*/
}
}
}
}
}
CAVEAT: this is just code off the top of my head. I might have left a few typos here and there, so don't expect it to run or even compile out of the box.
A couple of basic problems here. First, it is unlikely that the PC can reliably keep up with 115,200 baud data if you only read 10 bytes at a time with ReadFile. Try a slower baud rate and/or change the buffer size and number of bytes per read to something that will get around 20 milliseconds of data, or more.
Second, after you read some data put a nul at the end of it
szBuf[dwBytesRead] = 0;
before you pass it to printf or any other C string code.
I'm sending some data trough the socket, but I need to set the timeout.
I'm using something like:
fd_set rfds;
struct timeval tv;
int retval;
/* Watch stdin (fd 0) to see when it has input. */
FD_ZERO(&rfds);
FD_SET(sockDesc, &rfds);
/* Wait up to five seconds. */
tv.tv_sec = 5;
tv.tv_usec = 0;
retval = select(sockDesc + 1, &rfds, NULL, NULL, &tv);
if(rtn = ::recv(sockDesc, (raw_type*) buffer, bufferLen, 0)) < 0){
throw SocketException("error", true);
}
return rtn;
So.
Depending the type of data I return I need to implement timeout or not.
If I just send text data I don't need, if I send one file I need...
To explain more or less I'm sending some data through a socket and processing on the other side.
So, if I send one tar:
while(readtar){
senddata
get processed data
}
but sometimes the data sent is just the header, so when the other side process data it doesn't needs to return data and the socket stops on read.
To illustrate:
cat file.tar | myprogram -c "tar -zvt"
So it don't return nothing until receive enough data to return the name of file.
If i just send one file and returns the "cat" i dont have this problem
echo "asjdoiajdlaijdkasdjlkas" | myprogram -c "cat"
or
cat HUGEFILE.tar | myprogram -c "cat" | tar -zvt
In this case it does the same thing, but is not on the server side... so it dont work for me.
Now.... If I just use the recv without the select when I return the data using the cat it works... no problems with that.
BUT if I implement the select the data comes messed up.
WITHOUT SELECT
send "command line text temp test"
recv "command line text temp test"
WITH
send "command line text temp test"
recv "commmand lin/ˆ
1k5d99ck"
it's just to illustrate what is happening
Client loop:
while(size = read(fileno(stdin), thebuffer, 10000)){
sock->send(thebuffer, size); // if this data is not enough the other side never sends the data back
sock->recv //receive data
}
On the other side I do
if(pid == 0){
//stuffs closes, dup2
execlp("bash", "bash", "-c", "run.c_str(), NULL); // if i use one tar -zvt i need a bunch of data to generate the return
}
else
while(size = read(fout[0], buffer, 10000) > 0)){
sock->send(buffer, size);
}
So.. if the data sent is not enough to generate on
If I could check if read have anything or on the stdin side if the execlp send a terminator I could solve the problem
It sounds like you are expecting your TCP recv() to return data to you in chunks of a particular size... however, TCP recv() does not work that way. TCP is stream-based, so the number of bytes returned by recv() may vary anywhere between 1 (or 0 if you are using non-blocking I/O) and the size of the buffer you passed in. It's then up to your receiving code to loop as necessary to re-concatenate the received data again.
Also, it looks like you are trying to print out un-terminated ASCII strings -- that would explain the garbage characters at the end of your second recv() example. (i.e. if you want to print out the received data bytes as a string, be sure to place a NUL/0 byte after the last received byte; recv() won't do that for you)