I am writing an extension for Chrome that uses native host messaging. The goal is to have Chrome open links in the OS default browser when running in app mode. Chrome implements the native host messaging over pipes to stdin and stdout of the native application. This is all well and good and I've got the extension talking to the native application. The problem I'm having is that the first 4 bytes of data contain the length of the following string, which for my purposes will always contain null characters. An example strace is shown below. What is the best way to deal with this? I'd like to use something like cin or getline, that will stall the program until input is received if possible.
Process 27964 attached
read(0, "~\0\0\0\"http://stackoverflow.com/qu"..., 4096) = 130
read(0,
This is the current C++ code. I've tried variations using cin.get and fgets, but they don't wait on input and Chrome kills the program after the loop runs amok.
#include <string>
#include <iostream>
using namespace std;
int main(int argc, char* argv[]) {
for(;;) {
string message;
cin >> message;
if(!message.length()) break;
string cmd(string("xdg-open ") + message);
system(cmd.c_str());
}
return 0;
}
As far as I understand here, the length should be in native byte order, so the same endianness that your compiler uses for the same CPU architecture:
each message is serialized using JSON, UTF-8 encoded and is preceded
with 32-bit message length in native byte order.
This means that you could read first the length:
uint32_t len;
while (cin.read(reinterpret_cast<char*>(&len), sizeof (len))) // process the messages
{
// you know the number of bytes in the message: just read them
string msg (len, ' '); // string filled with blanks
if (!cin.read(&msg[0], len) )
/* process unexpected error of missing bytes */;
else /* process the message normally */
}
Related
I making C++ Console what can Communicatable with Serial ("COM3") Port.
The Serial has API.
API
km.move(int,int)
print(string) Examples : print('hello, world?')
km.delay(int)
Serial's Spec
BaudRate : 115200
ByteSize : 8
StopBits : 1
Parity : NONE
I tested it with uPyCraft IDE, Putty.
uPyCraft
Putty
it works perfectly, so I make a one C++ Console (Serilib Library Included) and tried to writeFile.
but only sometimes it works fine, mostly it doesn't work.
I think it is buffer size problems, but I don't know how to find and fix them.
I tested it with below code
int serialib::writeString(const char *receivedString,int arg)
{
DWORD dwBytesWritten;
if(!WriteFile(hSerial,receivedString,arg,&dwBytesWritten,NULL))
return -1;
if (!dwBytesWritten)
return -1;
return 1;
}
int main()
{
serial.openDevice("COM3", 115200,SERIAL_DATABITS_16,SERIAL_PARITY_NONE,SERIAL_STOPBITS_1);
if (serial.isDeviceOpen() != true)
{
return 1;
}
while (true)
{
string str;
cin >> str;
serial.writeString(str.c_str(), 32);
if (!cin) break;
}
}
The Situations
serial.writeString(str.c_str(), 17~32);
km.move(0,20)
=> Works fine. (string length is 13) (sec arg should be 17~32)
Second arg is size, changable 17~32 all was good
serial.writeString(str.c_str(), str.size());
km.move(0,20)
=> Doesn't work. (string length is 13, same with above.) (sec arg isn't 17~32)
Second arg is 13
serial.writeString(str.c_str(), 17~32);
km.move(0,20); -- Included ";"
=> Doesn't work. (when ; included, it was stacky, and all stack will work at same time when "The Situations" what Works fine.)
but it was stacky. I mean multiple of km.move(0,-32767 ~ 32767); doesn't work but it seems to be stacking.
and when I send a km.move(0,0~9); or km.move(0,10) (string size should be 13 and it doesn't care what ";" is included or not, just only get affected with string length. I don't know why)
all of stack what I sended is work at same time.
serial.writeString(str.c_str(),17~32);
km.move(0,1);
=> Works fine. (That mean string length should be 13)
I think why this problems are causing is serial's bytesize.
because all of "The Situations" are doesn't work when I tried this serial.openDevice("COM3", 115200,SERIAL_DATABITS_5~7,SERIAL_PARITY_NONE,SERIAL_STOPBITS_1);
Result
DATABITS should be greater than 8.
string length should be 13.
bytesize should be 17~32.
included ";" causing stack
In Putty or uPyCraft, string length doesn't care for work.
Someone help me for communicating with serial port at C++
I think why this problems are causing is serial's bytesize.
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 a client-server application, with the server part written in C++ (Winsock) and the client part in Java.
When sending data from the client, I first send its length followed by the actual data. For sending the length, this is the code:
clientSender.print(text.length());
where clientSender is of type PrintWriter.
On the server side, the code that reads this is
int iDataLength;
if(recv(client, (char *)&iDataLength, sizeof(iDataLength), 0) != SOCKET_ERROR)
//do something
I tried printing the value of iDataLength within the if and it always turns out to be some random large integer. If I change iDataLength's type to char, I get the correct value. However, the actual value could well exceed a char's capacity.
What is the correct way to read an integer passed over a socket in C++ ?
I think the problem is that PrintWriter is writing text and you are trying to read a binary number.
Here is what PrintWriter does with the integer it sends:
http://docs.oracle.com/javase/7/docs/api/java/io/PrintWriter.html#print%28int%29
Prints an integer. The string produced by String.valueOf(int) is
translated into bytes according to the platform's default character
encoding, and these bytes are written in exactly the manner of the
write(int) method.
Try something like this:
#include <sys/socket.h>
#include <cstring> // for std::strerror()
// ... stuff
char buf[1024]; // buffer to receive text
int len;
if((len = recv(client, buf, sizeof(buf), 0)) == -1)
{
std::cerr << "ERROR: " << std::strerror(errno) << std::endl;
return 1;
}
std::string s(buf, len);
int iDataLength = std::stoi(s); // convert text back to integer
// use iDataLength here (after sanity checks)
Are you sure the endianness is not the issue? (Maybe Java encodes it as big endian and you read it as little endian).
Besides, you might need to implement receivall function (similar to sendall - as here). To make sure you receive exact number of bytes specified - because recv may receive fewer bytes than it was told to.
You have a confusion between numeric values and their ASCII representation.
When in Java you write clientSender.print(text.length()); you are actually writing an ascii string - if length is 15, you will send characters 1 (code ASCII 0x31) and 5 (code ASCII 0x35)
So you must either :
send a binary length in a portable way (in C or C++ you have hton and ntoh, but unsure in Java)
add a separator (newline) after the textual length from Java side and decode that in C++ :
char buffer[1024]; // a size big enough to read the packet
int iDataLength, l;
l = recv(client, (char *)&iDataLength, sizeof(iDataLength), 0);
if (l != SOCKET_ERROR) {
buffer[l] = 0;
iDataLength = sscanf(buffer, "%d", &iDataLength);
char *ptr = strchr(buffer, '\n');
if (ptr == NULL) {
// should never happen : peer does not respect protocol
...
}
ptr += 1; // ptr now points after the length
//do something
}
Java part should be : clientSender.println(text.length());
EDIT :
From Remy Lebeau's comment, There is no 1-to-1 relationship between sends and reads in TCP. recv() can and does return arbitrary amounts of data, so you cannot assume that a single recv() will read the entire line of text.
Above code should not do a simple recv but be ready to concatenate multiple reads to find the separator (left as exercise for the reader :-) )
I'm writing a small sockets program (GNU libc). I have a loop which asks user for input (e.g. "MSG> "). When the user presses enter the message is sent (currently to a server on localhost).
Anyway, I want to read from stdin into a char buffer[256]. I'm currently using fgets() which doesn't do what I want. I'm not sure how write the code such that I ask the user and then get data 256 -1 bytes at a time so that I can send a c-string of 1000 bytes via several strings of 256 bytes.
EDIT: Add code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BUFSIZE 256
int main(int argc, char *argv[])
{
char msg[BUFSIZE];
size_t msgLen;
msgLen = strlen(fgets(msg, BUFSIZE, stdin));
puts(msg);
// This simply checks whether we managed to fill the buffer and tries to get
// more input
while (msgLen == (BUFSIZE - 1))
{
memset (msg, '\0', BUFSIZE);
fread(msg, BUFSIZE, 1, stdin);
msg[BUFSIZE - 1] = '\0';
msgLen = strlen(msg);
puts(msg);
if (msgLen < (BUFSIZE - 1))
break;
}
return 0;
}
You're implementing a loop to ensure 1000 bytes are recieved, right? The loop should indicate that it's counting up to 1000, for the sake of legibility. Keep track of the number of bytes you read (using the += operator), and use that number in the loop condition.
You seem to assume that fread will read 255 bytes, but this is under the invalid assumption that 255 bytes are available. When less than 255 bytes are read, this doesn't necessarily indicate an error; keep reading! When the return value of fread is less than zero, then you should be worried. Make sure you handle those situations.
How about this:
fread(buffer, sizeof(buffer), 1, stdin);
If you're using fgets(), you're using the standard IO library. You're going to want to use fread() then (instead of, say, read(), which uses a file descriptor), to specify the number of bytes to read. See: http://www.cplusplus.com/reference/cstdio/fread/
You may consider using the read function for buffered input. It takes an open file descriptor (STDIN_FILENO for stdin), a pointer to a buffer (char *) and the count of bytes to read. See the manual entry for more details.
I know this question is scattered all over the internet, but still, nothing is getting me completely there yet. I want to write data to a serial port in C++ (linux) for a a Propeller board. Program works fine when taking input from the console, but when I write strings to it always return: ERROR - Invalid command from the device. I tried creating array of char with Hex values then it worked. here's a working code, below. But how will i be able to just provide a string variable of command and send it to the serial port? perhaps, how do you I convert it to hex values if it's the only way? Thanks everyone
note: the loop is to use user input from console. What i need is a way to send a string variable to the serial port.
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
int main(int argc,char** argv){
struct termios tio;
struct termios stdio;
int tty_fd;
fd_set rdset;
unsigned char c='D';
printf("Please start with %s /dev/ttyS1 (for example)\n",argv[0]);
memset(&stdio,0,sizeof(stdio));
stdio.c_iflag=0;
stdio.c_oflag=0;
stdio.c_cflag=0;
stdio.c_lflag=0;
stdio.c_cc[VMIN]=1;
stdio.c_cc[VTIME]=0;
tcsetattr(STDOUT_FILENO,TCSANOW,&stdio);
tcsetattr(STDOUT_FILENO,TCSAFLUSH,&stdio);
fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK); // make the reads non-blocking
memset(&tio,0,sizeof(tio));
tio.c_iflag=0;
tio.c_oflag=0;
tio.c_cflag=CS8|CREAD|CLOCAL; // 8n1, see termios.h for more information
tio.c_lflag=0;
tio.c_cc[VMIN]=1;
tio.c_cc[VTIME]=5;
tty_fd=open(argv[1], O_RDWR | O_NONBLOCK);
cfsetospeed(&tio,B115200); // 115200 baud
cfsetispeed(&tio,B115200); // 115200 baud
tcsetattr(tty_fd,TCSANOW,&tio);
//char str[] = {'V','E','R','\r'};
//the above str[] doesn't work although it's exactly the same as the following
char str[] = {0x56, 0x45, 0x52, 0x0D};
write(tty_fd,str,strlen(str));
if (read(tty_fd,&c,1)>0)
write(STDOUT_FILENO,&c,1);
while (c!='q')
{
if (read(tty_fd,&c,1)>0) write(STDOUT_FILENO,&c,1); // if new data is available on the serial port, print it out
if (read(STDIN_FILENO,&c,1)>0)
if(c!='q')
write(tty_fd,&c,1); // if new data is available on the console, send it to the serial port
}
close(tty_fd);
}
I'm happy to solve my own solution but yet disappointed to not have seen the trivial matter much sooner. char by default are signed in c++, which makes it holding the range -128 to 127. However, we are expecting the ASCII values which are 0 to 255. Hence it's as simple as declaring it to be unsigned char str[] and everything else should work. Silly me, Silly me.
Still, Thank you everyone for helping me!!!
Are you sure you should end with '\r'? When entering text from console the return key will result in a '\n' character (on Linux) and not '\r'
Also error checking is missing on most functions (open(), fcntl(), etc.). Maybe one of these functions fail. To find out how to check for errors read the man page (for example man 2 open for the open() command. In case of open() the man page explains it returns -1 when it could not open the file/port.
After your edit you wrote:
char str[] = {0x56, 0x45, 0x52, 0x0D};
write(tty_fd,str,strlen(str));
which is wrong. strlen expects a '\0' terminated string which str is obviously not so now it sends your data and whatever there is in memory until it sees a '\0'. You need to add 0x00 to your str array.