Sending/Receiving serial port (COM) data with C++ Handle - c++

I need some help with understanding how to use ReadFile and WriteFile in C++ while using method shown in this guide:
https://www.delftstack.com/howto/cpp/cpp-serial-communication/
My question is, how to use these two functions to send or receive anything? I don't know how to call them properly
I start with Handle:
// Open serial port
HANDLE serialHandle;
serialHandle = CreateFile(L"COM3", GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
Next I did some basic settings like setting baud, bytesize etc. I will skip that. And here we come to my problem.
I tried to send some data and receive it (my cable output and input pins are connected). Problem is I don't know how to call ReadFile and WriteFile properly. Here's how I tried to do it:
char sBuff[n + 1] = { 0 };
DWORD send = 0;
cout << "Sent: " << WriteFile(serialHandle, sBuff, n, &send, NULL) << endl;
DWORD dwRead = 0;
cout << "Received: " << ReadFile(serialHandle, sBuff, n, &dwRead, NULL) << endl;
CloseHandle(serialHandle);
}
}
It's just some attempt to guess the correct method. Any example with short explanation will be much appreciated.
Edit: removed useless chunk of code, hope my question is more understandable now

It's all about the handle "serialHandle" being set to the com3 port instead of the file.
The first question, in the layer where you write code, you should not worry about the synchronization or interference of sending and receiving. The serial port handler coordinates it.
Second question, your data is sent as a string of characters that are ASCII. You have to write a function called extract(reciedData) in receiving and place your variables in integer or double or string. In fact, you need a protocol, for example, NMEA .
please search aboat NMEA protocol in google

Related

C++ Windows recv() doesn't return even if data are available

I'm writing a C++ program. I need to receive a file and I'm using recv() function over a TCP socket to do that.
download_file() {
while (left_bytes != 0 && !connection_closed) {
if (left_bytes >= buffer_max_size)
bytes_to_download = buffer_max_size;
else
bytes_to_download = left_bytes;
if (request.conn->read_data(buffer, bytes_to_download))
{
left_bytes -= buffer->get_size();
temporary_file.write_data(buffer);
} else connection_closed = true;
}
}
read_data() {
while (bytes_received < size && alive_) {
bytes_read = recv(sock_, read_buffer, size, 0);
if (bytes_read == SOCKET_ERROR) {
delete[] local_buffer;
throw SocketException(WSAGetLastError());
}
// the connection is closed
if (bytes_read == 0) alive_ = false;
else {
bytes_received += bytes_read;
buffer->add(local_buffer, bytes_read);
}
}
}
The problem is that the recv never returns. It receives the whole file except for few KB and it freeze on the recv(). The buffer size is 1460.
I receive the file only if I print something to the console with cout every time the recv is called. Only in this case I receive the whole file.
Otherwise if I set as socket option the WAITALL and the client closes the connection after the file is sent, I receive the whole file.
Here's the code for the Client side that sends the file:
TransmitFile(file_request->connection_->get_handle_socket(), file_handler.get_file_handle(), file_request->file_size_, 65535, nullptr, nullptr, TF_USE_SYSTEM_THREAD)
EDIT
Here's how I send and read the file size between the Client and Server.
std::stringstream stream_;
stream_.str(std::string());
// append the file size
const __int64 file_size = htonll(GetFileSize(file_handle_, nullptr););
stream_ << ' ' << file_size << ' ';
Then I use the send to send this string
Here's how I read the file size
// Within stream_ there is all the content of the received packet
std::string message;
std::getline(stream_, message, ' ');
this->request_body_.file_size_ = ntohll(strtoll(message.c_str(), nullptr, 0));
EDIT
I cleaned up the code and I found out that read_data() is obviously called once and I was updating the buffer variable wrongly. Hence I was tracking the size of the content within the buffer in a wrong way which make me call the recv() once more.
First thing: recv() will block if there are no bytes left to read but the connection is still open. So whatever you might say about what your code is doing, that must be what is happening here.
That could be for any of the following reasons:
the sender lied about the size of the file, or did not send the promised number of bytes
the file size was not interpreted correctly at the receiving end for whatever reason
the logic that 'counts down' the number of bytes left in the receiver is somehow flawed
Trouble is, looking at the code samples you have posted, it's hard to say which because the code is a bit muddled and, in my eyes, more complicated than it needs to be. I'm going to recommend you sort that out.
Sending the size of the file.
Don't mess about sending this as a string. Send it instead in binary, using (say) htonll() at the sending end and ntohll() at the receiving end. Then, the receiver knows to read exactly 8 bytes to figure out what's coming next. It's hard to get that wrong.
Sending the file itself.
TransmitFile() looks to be a good choice here. Stick with it.
Receiving the file and counting down how many bytes are left.
Take a closer look at that code and consider rewriting it. It's a bit of a mess.
What to do if it still doesn't work.
Check with WireShark that the expected data is being sent and then walk through the code in the receiver in the debugger. There is absolutely no excuse for not doing this unless you don't have a debugger for some reason, in which case please say so and somebody will try to help you. The fact that logging to cout fixes your problems is a red-herring. That just changes the timing and then it just happens to work right.
That's all. Best of luck.

Basic Named Pipe to send data between c++ programs?

I know this has been asked before but I just can't find the answer so I am posting for some help.
I have a DLL, which once injected into a process creates a named pipe. The pipe will wait until a client is connected and will send data to the client until the client disconnects.
The client side, it will just connect to the pipe and receive data and do things with such data.
My question is, I want to be able to send more than 1 type of data, for example, float, int, strings, etc. How do I reconstruct the data into correct data (float, int strings and such)?
Here is my code for the client :
HANDLE hPipe;
DWORD dwWritten;
char Buffer[1024];
hPipe = CreateFile(TEXT("\\\\.\\pipe\\Pipe"),
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
0,
NULL);
if (hPipe != INVALID_HANDLE_VALUE)
{
WriteFile(hPipe,
Buffer, //How do I put all the data into a buffer to send over to the client?
sizeof(Buffer), // = length of string + terminating '\0' !!!
&dwWritten,
NULL);
CloseHandle(hPipe);
}
The Server :
wcout << "Creating Pipe..." << endl;
HANDLE hPipe;
char buffer[1024];
DWORD dwRead;
hPipe = CreateNamedPipe(TEXT("\\\\.\\pipe\\Pipe"),
PIPE_ACCESS_DUPLEX,
PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, // FILE_FLAG_FIRST_PIPE_INSTANCE is not needed but forces CreateNamedPipe(..) to fail if the pipe already exists...
1,
1024 * 16,
1024 * 16,
NMPWAIT_USE_DEFAULT_WAIT,
NULL);
while (hPipe != INVALID_HANDLE_VALUE)
{
if (ConnectNamedPipe(hPipe, NULL) != FALSE) // wait for someone to connect to the pipe
{
while (ReadFile(hPipe, buffer, sizeof(buffer) - 1, &dwRead, NULL) != FALSE)
{
/* add terminating zero */
buffer[dwRead] = '\0';
/* do something with data in buffer */
printf("%s", buffer);
}
}
DisconnectNamedPipe(hPipe);
}
My problem is, I have a bunch of data I would like to send to the client in 1 go, which could contain things like float, int, double, etc. Once I gather all the data from the server, I would like to send it to the client and have the client parse it by splitting the data like so :
void split(const string& s, char c,
vector<string>& v) {
string::size_type i = 0;
string::size_type j = s.find(c);
while (j != string::npos) {
v.push_back(s.substr(i, j - i));
i = ++j;
j = s.find(c, j);
if (j == string::npos)
v.push_back(s.substr(i, s.length()));
}
}
I'm sort of lost on how I can send all my data over to the client and correctly get the original value?
You have to use a library that converts your data to something which can be send over a socket. This is called a serializer! You can use a serializer also for serializing into data stream or maybe also in a GUI or whatever. Receiving the data simply needs "deserialize".
You can find a lot of seriaizer libs like:
http://www.boost.org/doc/libs/1_66_0/libs/serialization/doc/index.html
https://uscilab.github.io/cereal/
many many more!
The custom code can look like ( pseudo code! ):
class Check
{
int i;
float f;
template<SERIALIZER_TYPE>
void Serialize( SERIALIZER_TYPE& ser )
{
ser & i & f;
}
};
int main()
{
Check c;
std::string s;
Socket socket( ip, port );
WriteSerializer ser(socket);
ser & c & s;
}
As you can see, you have nothing to write your self for "knowing" how data types are serialized. Classes/structs have to provide a serializer method, so that they also can be split into there native data types.
Edit:
Added question from comments:
Is it possible to send this data from my DLL to the EXE through named pipe instead of saving the file?
For cereal taken from the docs:
cereal comes with excellent standard library support as well as binary, XML, and JSON serializers. If you need something else, cereal was written to be easily extensible for adding custom serialization archives or types.
So one option is simply to write the new interface for your needs.
But take a look into the example code:
void x()
{
std::ofstream file( "out.xml" );
cereal::XMLOutputArchive archive( file ); // depending on the archive type, data may be
// output to the stream as it is serialized, or
// only on destruction
archive( some_data, more_data, data_galore );
}
As you can see there is used a std::ofstream as output. So you can simply use that ofstream which is opened for a socket.
How you can connect a std::ostream with a socket is answered e.g. here:
How can I create an 'ostream' from a socket?
But it is quite simply to this job also by hand. You simply have to write your own buffer class for the socket and connect it to a ofstream. Not more then 10 lines of code I believe!
As a result you can stream now your variables and objects as xml, json or whatever over a socket.
Edit: From the comments: Yes, using a pipe instead a socket will also be adaptable to iostream and the technique is exactly the same and based on implementing something around streambuf.
c++ connect output stream to input stream
I am in hope that on windows it will work the same way and istream is also as ostream adaptable.
To go more in details about a complete solution will not longer fit here in Q&A style I believe. So if there are further questions about connecting something to iostream, please start new question!
If you use WriteFile API to write to pipe, then you can send Buffer of bytes. I like #Klaus idea about serialization to pack all your data and if I need to send objects over pipe from client to server it would be my implementation of choice.
However I consider it overkill if you need to send just some pair of data (like "abc 1.12345"). I would simply put them in the buffer with known delimiter and send from server to client, and then just parse the string on the client.
Answering on your question "//How do I put all the data into a buffer to send over to the client?"
Here's some code snippets:
std::string strToSend;
// ... some initialization
std::wstring wstr = std::wstring(strToSend.begin(), strToSend.end());
LPTSTR pchStr = wstr.c_str();
LPCTSTR pchSend;
StringCchCopy( pchSend, 1024, pchStr );
Use pchSend in WriteFile(hPipe, pchSend, ... call.
Please also check the following example for some code ideas: Named Pipe Client
First of all we need to understand what is a pipe here. Pipe and Queue are medium for communication between multiple process. Every message you submit/drop in a queue or pipe are unique as one set of message and while you are reading it, will read only one message at a time. If you put 10, 20.45 and “Hellow” into a pipe and read them from a client it will read 10 as first message 20.45 as second message and “Hellow” as third message. Normally they will be coming a string value which you need to convert into appropriate type. You should have your own logic to check whether a value is int or float or a normal string. First just read the data and print them all and think how to cope up with them.

Microsoft Windows API Serial ReadFile Producing Unexpected Output

I am currently trying to write a program that will read Bluetooth output from an Arduino HC-05 module on a Serial Communications Port.
http://cdn.makezine.com/uploads/2014/03/hc_hc-05-user-instructions-bluetooth.pdf
When I open a Putty terminal and tell it to listen to COM4, I am able to see the output that the program running on the Arduino is printing.
However, when I run the following program to try to process incoming data on the serial port programatically, I get the output shown.
#include <Windows.h>
#include <string>
#include <atltrace.h>
#include <iostream>
int main(int argc, char** argv[]) {
HANDLE hComm = CreateFile(
L"COM4",
GENERIC_READ | GENERIC_WRITE,
0,
0,
OPEN_EXISTING,
NULL,
0
);
if (hComm == INVALID_HANDLE_VALUE) {
std::cout << "Error opening COM4" << std::endl;
return 1;
}
DWORD dwRead;
BOOL fWaitingOnRead = false;
OVERLAPPED osReader = { 0 };
char message[100];
osReader.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (osReader.hEvent == NULL) {
std::cout << "Error creating overlapping event" << std::endl;
return 2;
}
while (1) {
if (!fWaitingOnRead) {
if (!ReadFile(
hComm,
&message,
sizeof(message),
&dwRead,
NULL
)) {
if (GetLastError() != ERROR_IO_PENDING) {
std::cout << "Communications error" << std::endl;
return 3;
}
}
else {
message[100] = '\0';
std::cout << message << std::endl;
}
}
}
return 0;
}
I have made changes to the handle and the ReadFile function call so that it will be making the calls synchronously in an infinite loop. However, Visual Studio pops up a warning saying that the program has stopped working then asks to debug or close program. My assumption is that it must be stalling somewhere or failing to execute some WindowsAPI function somewhere up the stack.
Any help, pointers, greatly appreciated.
At least IMO, using overlapped I/O for this job is pretty severe overkill. You could make it work, but it would take a lot of extra effort on your part, and probably accomplish very little.
The big thing with using comm ports under Windows is to set the timeouts to at least halfway meaningful values. When I first did this, I started by setting all of the values to 1, with the expectation that this would sort of work, but probably consume excessive CPU time, so I'd want to experiment with higher values to retain fast enough response, while reducing CPU usage.
So, I wrote some code that just set all the values in the COMMTIMEOUTS structure to 1, and setup the comm port to send/read data.
I've never gotten around to experimenting with longer timeouts to try to reduce CPU usage, because even on the machine I was using when I first wrote this (probably a Pentium II, or thereabouts), it was functional, and consumed too little CPU time to care about--I couldn't really see the difference between the machine completely idle, and this transferring data. There might be circumstances that would justify more work, but at least for any need I've had, it seems to be adequate as it is.
That's because message has the wrong type.
To contain a string, it should be an array of characters, not an array of pointers to characters.
Additionally, to treat it as a string, you need to set the array element after the last character to '\0'. ReadFile will put the number of characters it reads into dwRead.
Also, it appears that you are not using overlapped I/O correctly. This simple program has no need for overlapped I/O - remove it. (As pointed out by #EJP, you are checking for ERROR_IO_PENDING incorrectly. Remove that too.)
See comments below, in your program:
if (!fWaitingOnRead) {
if (!ReadFile( // here you make a non-blocking read.
hComm,
message,
sizeof(*message),
&dwRead,
&osReader
)) {
// Windows reports you should wait for input.
//
if (GetLastError() != ERROR_IO_PENDING) {
std::cout << "Communications error" << std::endl;
return 3;
}
else { // <-- remove this.
// insert call to GetOverlappedcResult here.
std::cout << message << std::endl;
}
}
}
return 0; // instead of waiting for input, you exit.
}
After you call ReadFile() you have to insert a call for GetOverlappedResult(hComm, &osReader, &dwBytesRceived, TRUE) to wait for the read operation to complete and have some bytes in your buffer.
You will also need to have a loop in your program if you don't want to exit prematurely.
If you do not want to do overlapped i/o (which is a wise decision) , do not pass an OVERLAPPED pointer to ReadFile. ReadFile will block until it has some data to give you. You will then obviously not need to call GetOverlappedresult()
For the serial port, you also need to fill in a DCB structure. https://msdn.microsoft.com/en-us/library/windows/desktop/aa363214(v=vs.85).aspx
You can use BuildCommDCB()to initialize it. There is a link to it in the MS doc, CallGetCommState(hComm, &dcb) to initialize the serial port hardware. The serial port needs to know which baud rate etc. you need for your app.

How can I stop C++ recv() when string read is finished?

I am reading an Image URL sent from a Java client to a C++ server from Sockets. The server stops reading through recv() when it detects there is a null character in the char buffer[] as I do below in the following code:
void * SocketServer::clientController(void *obj)
{
// Retrieve client connection information
dataSocket *data = (dataSocket*) obj;
// Receive data from a client step by step and append data in String message
string message;
int bytes = 0;
do
{
char buffer[12] = {0};
bytes = recv(data->descriptor, buffer, 12, 0);
if (bytes > 0) // Build message
{
message.append(buffer, bytes);
cout << "Message: " << message << endl;
}
else // Error when receiving it
cout << "Error receiving image URL" << endl;
// Check if we are finished reading the image link
unsigned int i = 0;
bool finished = false;
while (i < sizeof(buffer) / sizeof(buffer[0]) && !finished)
{
finished = buffer[i] == '\0';
i++;
}
if (finished)
break;
}
while (bytes > 0);
cout << message << endl;
close(data->descriptor);
pthread_exit(NULL);
}
Is there a better and more elegant way to make this?
I read about sending first the size of the URL, but I do not know exactly how to stop recv() with it. I guess it is done by counting the bytes received until the size of the URL is reached. At that moment, we should be finished reading.
Another approach could be closing the Java socket so that recv() will return -1 and the loop will be finished. However, considering my Java client waits for a response from C++ server, closing the socket and then reopen it does not seem a suitable option.
Thank you,
Héctor
Apart from that your buffer has an unusual size (one typically chooses a power of 2, so 8, 16, 32, ...) and it looks a little small for your intent, your approach seems fine to me:
I assume that your java client will send a null terminated string and then wait anyway, i. e. especially it does not send any further data. So after you received the 0 character, there won't be any data to receive any more anyway, so there is not need to bother for something explicitly that recv does implicitly (recv normally returns only the data available, even if less than the buffer could consume).
Be aware that you initialized buffer with 0, so if you check the entire buffer (instead of the range [buffer, buffer + bytes), you might detect a false positive (if you receive less than 12 characters in the first iteration)! Detection of the 0 character can be done more elegantly, though, anyway:
if(std::find(buffer, buffer + bytes, 0) < buffer + bytes)
{
// found the 0 character!
break;
}

recv() issues with delay

This question has been asked a number of times, I have noted, but none of the solutions seem to be applicable to me. Before I continue I will post a little bit of code for you:
// Await the response and stream it to the buffer, with a physical limit of 1024 ASCII characters
stringstream input;
char buffer[4096*2];
while (recv(sock, buffer, sizeof(buffer) - 1, MSG_WAITALL) > 0)
input << buffer;
input << '\0';
// Close the TCP connection
close(sock);
freehostent(hostInfo);
And here is my request:
string data;
{
stringstream bodyStream;
bodyStream
<< "POST /api/translation/translate HTTP/1.1\n"
<< "Host: elfdict.com\n"
<< "Content-Type: application/x-www-form-urlencoded\n"
<< "Content-Length: " << (5 + m_word.length())
<< "\n\nterm=" << m_word;
data = bodyStream.str();
}
cout << "Sending HTTP request: " << endl << data << endl;
I am very new to this sort of programming (and stack overflow- preferring to slog it out and bang my head against a wall until I solve problems myself but I'm lost here!) and would really appreciate help working out why it takes so long! I've looked into setting it up so that it is non-blocking, but had issues getting that to work as expected. Though maybe people here could point me in the right direction, if the non-bocking route is the way I need to go.
I have seen that a lot of people prefer to use libraries but I want to learn to do this!
I'm also new to programming on the mac and working with sockets. Probably not the best first time project maybe, but I've started now! So I wish to continue :) Any help would be nice!
Thank you in advance!
The reason why it takes a long time to receive is because you tell the system to wait until it has received all data you ask for, i.e. 8k bytes, or there is an error on the connection or it is closed. This is what the flag MSG_WAITALL does.
One solution to this is to make the socket non-blocking, and do a continuous read in a loop until we get an error or the connection is closed.
How to make a socket non-blocking differs depending on platform, on Windows it done with the ioctlsocket function, on Linux or similar systems it is done with the fcntl function:
int flags = fcntl(sock, F_GETFL, 0);
flags |= O_NONBLOCK;
fcntl(sock, F_SETFL, flags);
Then you read from the socket like this:
std::istringstream input;
for (;;)
{
char buffer[256];
ssize_t recvsize;
recvsize = recv(sock, buffer, sizeof(buffer) - 1, 0);
if (recvsize == -1)
{
if (errno != EAGAIN && errno != EWOULDBLOCK)
break; // An error
else
continue; // No more data at the moment
}
else if (recvsize == 0)
break; // Connection closed
// Terminate buffer
buffer[recvsize] = '\0';
// Append to input
input << buffer;
}
The problem with the above loop is that if no data is ever received, it will loop forever.
However, you have a much more serious problem in your code: You receive into a buffer, and then you append it to the stringstream, but you do not terminate the buffer. You do not need to terminate the string in the stream, it's done automatically, but you do need to terminate the buffer.
This can be solved like this:
int rc;
while ((rc = recv(sock, buffer, sizeof(buffer) - 1, MSG_WAITALL)) > 0)
{
buffer[rc] = '\0';
input << buffer;
}
The problem here happens because you are specifying MSG_WAITALL flag. It forces the recv to remain blocked until all the specified bytes are received (sizeof(buffer) - 1 in your case, while the message being sent by the other party is obviously smaller) or an error occurs and it returns -1 with errno variable being set appropriately.
I think, a more preferable option would be to cause recv without any flags in a loop until the socket on the other end is closed (recv returns 0) or some separator is received.
However, you should be careful using input << buffer, because recv might return only a small portion of data (for example, 20 bytes) on each iteration, so you should put exactly this amount of data to string stream. The number of bytes received is returned by recv.