C++ Sockets - Client gives segmentation fault (linux) - c++

I created a server/client connection. The server and client both are compiling correctly but when I run the client, it gives me a Segmentation Fault (core dumped)
I don't know what I am doing wrong with my memory allocations. The program is not dangling or anything. I think my program is writing to a read-only portion of the memory, or maybe accessing a memory that is not available.
If anyone can tell where is the bug I would really appreciate it.
client.cpp
#include <iostream>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <stdlib.h>
#include <unistd.h>
using namespace std;
int main() {
char a;
int client;
int portNum = 1500;
int bufsize = 1024;
char* buffer = new char (bufsize);
bool isExit = false;
char* ip;
strcpy(ip, "127.0.0.1");
struct sockaddr_in direc;
if ((client = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
cout << "Error creating socket..." << endl;
exit(0);
}
cout << "Enter # to end call" << endl;
cout << "\t\t\t[s] to begin with" << endl;
cin >> a;
cout << "Socket created successfully..." << endl;
direc.sin_family = AF_INET;
direc.sin_port = htons(portNum);
inet_pton(AF_INET, ip, &direc.sin_addr);
if (connect(client,(struct sockaddr *)&direc, sizeof(direc)) == 0)
cout << "Connection to the server " << inet_ntoa(direc.sin_addr) << endl;
cout << "Awaiting confirmation from the server..." << endl;
recv(client, buffer, bufsize, 0);
cout << "Response received: " << buffer;
cout << "\nRemember to put an asterisk at the end to send a message * \n Enter # to terminate the connection" << endl;
do {
cout << "Enter a message: ";
do {
cin >> buffer;
send(client, buffer, bufsize, 0);
if (*buffer == '#') {
send(client, buffer, bufsize, 0);
*buffer = '*';
isExit = true;
}
} while (*buffer != 42);
cout << "Mensage received: ";
do {
recv(client, buffer, bufsize, 0);
cout << buffer << " ";
if (*buffer == '#') {
*buffer = '*';
isExit = true;
}
} while (*buffer != 42);
cout << endl;
} while (!isExit);
cout << "Connection terminated. END PROGRAM\n\n";
close(client);
return 0;
}
I am assuming you don't need the server.cpp since it's all good and waiting for incoming connections.
Thanks!

There are a number of problems with this code, but the immediate and fatal errors are:
int bufsize = 1024;
char* buffer = new char (bufsize);
Allocates 1 character and tries to store the value of bufsize into it. bufsize is too big, so it gets truncated to 0. End result, buffer points to a single character, not an array of 1024, and that single value is set to 0. When you attempt to read bufsize bytes into buffer, you almost certainly overrun that single character and the behaviour is undefined. Most likely it either destroys some other program data (and possibly causes problems later) or writes into invalid memory and crash immediately.
I believe you meant
int bufsize = 1024;
char* buffer = new char[bufsize];
Instead,
char buffer[1024];
Will do what you want. Instead of bufsize, use sizeof(buffer). Further the following is often preferable:
Up at the top of the file, right under the includes:
#define BUFSIZE 1024
and then
char buffer[BUFSIZE];
Now you can use BUFSIZE or sizeof(buffer). Both are resolved during compilation so there is no performance cost.
2018 Addendum:
constexpr int BUFSIZE = 1024;
Will have the same effect in modern C++ (C++11 or newer) and does not have the the downsides of macro substitution from the #define.
The beauty of both options is the memory is self-managed. char* buffer = new char[bufsize]; requires a delete[] buffer somewhere in your code to put the memory back. And you have to make sure you get to that delete[] to prevent a leak. Don't use pointers and dynamic allocation unless you have to.
Next,
char* ip;
strcpy(ip, "127.0.0.1");
allocates a pointer, ip that is uninitialized. Most likely the address if contains is made up of whatever crap happened to be on the stack and does not point to a valid char array. Then "127.0.0.1" is written over whatever happened to be pointed to by ip. Similar effect to overrunning the end of buffer earlier.
Again, we know exactly what ip is going to point at, so the fix is easy:
char * ip = "127.0.0.1";
I prefer
char ip[] = "127.0.0.1";
but I have no reason for doing so.
2018 Addendum: I now have a reason for doing so. char * ip = "127.0.0.1"; is flat-out illegal in modern C++. String literals are constant arrays, and assigning them to non constant pointers can lead to much badness if the pointer is used to modify the string literal. In the old days we just ignored the problem and never wrote to the literal. Except when you did a few abstractions later and spent days or weeks debugging. Better to just cut the problem off at the source and copy the literal to a mutable array if there is a chance that it might be mutated. Even better is to remain const correct throughout the code if you can.
Next up,
recv(client, buffer, bufsize, 0);
Has two problems:
It discards the number of bytes read and the error codes returned. The program has no idea if it read anything at all due to a socket error or if it got the entire message, part of the message or more than the message.
It also demonstrates a misunderstanding of how TCP works. TCP does not work in nice, defined messages. Data written into the socket may be packed into the same out-bound packet with other messages. It may be split up across multiple packets that will arrive at different times. The logic behind this is out of scope for StackOverflow. Do some reading on TCP and streaming data.
But wait! There is more!
cin >> buffer;
Will overflow buffer even if fixed to the expected size if the user types in 1024 or more characters (do not forget the null terminator is required). Further, you don't know how many characters were input without counting them yourself. Painful and slow. Fortunately there is std::string.
std::string outbuf;
cin >> outbuf;
Solves both problems in one shot. It resizes itself and keeps a count of its contents. Neat, huh?
send(client, buffer, bufsize, 0);
Will send 1024 bytes of data even if the user typed in less. Or more. Yuck. Using outbuf from above,
send(client, outbuf.c_str(), outbuf.length(), 0);
Writes the correct number of characters every time, but if you want to preserve the string's terminating null, you'll have to send outbuf.length() + 1 characters.

Related

C/C++ recv hangs altough local server sends data

I am having a hard time figuring out a bug in my TCP client-server app. The problem I am facing: in my recv function do-while loop, if the condition is bytes > 0, the function hangs forever. Replacing that with bytes == NMAX, everything works fine, UNLESS NMAX is equal to 1. A few side notes: doing a single send-recv works fine, but trying to do a send-recv and then recv-send hangs forever. NMAX is a constant set to 4096 by default. Server is ran first, then the client.
This is my send function:
ssize_t sendData(const std::string data, int fd)
{
ssize_t total = data.length(), bytes, sent = 0;
do
{
ssize_t chunk = total > NMAX ? NMAX : total;
bytes = send(fd, data.c_str() + sent, chunk, 0);
if (bytes == -1)
{
throw std::system_error(errno, std::generic_category(), "Error sending data");
}
total -= bytes;
sent += bytes;
} while (total > 0);
return sent;
}
This is my recv function:
std::string recvData(int fd)
{
ssize_t bytes;
std::string buffer;
do
{
std::vector<char> data(NMAX, 0);
bytes = recv(fd, &data[0], NMAX, 0);
if (bytes == -1)
{
throw std::system_error(errno, std::generic_category(), "Error receiving data");
}
buffer.append(data.cbegin(), data.cend());
} while (bytes > 0); // Replacing with bytes == NMAX partially fixes the issue, why?
return buffer;
}
This is the client's main function:
std::cout << "Sent " << sendData(data) << " bytes\n";
std::cout << "Received: " << recvData() << "\n";
And this is the server's main function:
std::cout << "Received: " << recvData(client) << "\n";
std::cout << "Sent " << sendData("Hello from the server side!", client) << " bytes\n";
The problem with your program is that the receiving side does not know how many bytes to receive in total. Therefore it will just endlessly try to read more bytes.
The reason why it "hangs" is that you perform a blocking system call (recv) which will only unblock if at least 1 more byte had been received. However since the peer does not send more data this will never happen.
To fix the issue you need to have a proper wire-format for your data which indicates how big the transmitted data is, or where it starts and ends. A common way to do this is to prefix data with it's length in binary form (e.g. a 32bit unsigned int in big endian format). Another way is to have indicators inside the data that indicate it's end (e.g. the \r\n\r\n line breaks in HTTP).
Btw: Your send function is not ideal for cases where data.length() == 0. In this case you perform a send system call with 0 bytes - which is rather unnecessary.

Having issues with sockets and telnet

I've been learning sockets, and I have created a basic server where you can telnet into and type messages, then press enter and the message is printed on the server.
Since it's telnet, every key press gets sent to the server. So I basically hold all sent bytes in a buffer, and then when a carriage return ("\r\n") is received, I discard that, and print out the clients current buffer. Then I clear the clients buffer.
My problem is that every once in a while (and I'm not quite sure how to replicate it), the first "line" of data I send in gets an extra space tacked onto each character. For example, I'll type "Test" on the telnet client, but my server will receive it as "T e s t ". I always clear the receiving buffer before receiving any data. One obvious solution is just to remove all spaces serverside, but then that messes up my ability to send more than one word. Is this just an issue with my telnet, or is there something I can do on the server to fix this?
I am using the WinSock2 API and Windows 10 Telnet.
EDIT:
I have checked the hex value of the extra character, and it is 0x20.
EDIT:
Here is the code that receives and handles the incoming telnet data.
// This client is trying to send some data to us
memset(receiveBuffer, sizeof(receiveBuffer), 0);
int receivedBytes = recv(client->socket, receiveBuffer, sizeof(receiveBuffer), 0);
if (receivedBytes == SOCKET_ERROR)
{
FD_CLR(client->socket, &masterFDSet);
std::cerr << "Error! recv(): " << WSAGetLastError() << std::endl;
closesocket(client->socket);
client->isDisconnected = true;
continue;
}
else if (receivedBytes == 0)
{
FD_CLR(client->socket, &masterFDSet);
std::cout << "Socket " << client->socket << " was closed by the client." << std::endl;
closesocket(client->socket);
client->isDisconnected = true;
continue;
}
// Print out the hex value of the incoming data, for debug purposes
const int siz_ar = strlen(receiveBuffer);
for (int i = 0; i < siz_ar; i++)
{
std::cout << std::hex << (int)receiveBuffer[i] << " " << std::dec;
}
std::cout << std::endl;
std::string stringCRLF = "\r\n"; // Carraige return representation
std::string stringBS = "\b"; // Backspace representation
std::string commandBuffer = receiveBuffer;
if (commandBuffer.find(stringCRLF) != std::string::npos)
{
// New line detected. Process message.
ProcessClientMessage(client);
}
else if (commandBuffer.find(stringBS) != std::string::npos)
{
// Backspace detected,
int size = strlen(client->dataBuffer);
client->dataBuffer[size - 1] = '\0';
}
else
{
// Strip any extra dumb characters that might have found their way in there
commandBuffer.erase(std::remove(commandBuffer.begin(), commandBuffer.end(), '\r'), commandBuffer.end());
commandBuffer.erase(std::remove(commandBuffer.begin(), commandBuffer.end(), '\n'), commandBuffer.end());
// Add the new data to the clients data buffer
strcat_s(client->dataBuffer, sizeof(client->dataBuffer), commandBuffer.c_str());
}
std::cout << "length of data buffer is " << strlen(client->dataBuffer) << std::endl;
You have two major problems.
First, you have a variable, receivedBytes that knows the number of bytes you received. Why then do you call strlen? You have no guarantee that the data you received is a C-style string. It could, for example, contain embedded zero bytes. Do not call strlen on it.
Second, you check the data you just received for a \r\n, rather than the full receive buffer. And you receive data into the beginning of the receive buffer, not the first unused space in it. As a result, if one call to recv gets the \r and the next gets the \n, your code will do the wrong thing.
You never actually wrote code to receive a message. You never actually created a message buffer to hold the received message.
Your code, my comments:
memset(receiveBuffer, sizeof(receiveBuffer), 0);
You don't need this. You shouldn't need this. If you do there is a bug later in your code.
int receivedBytes = recv(client->socket, receiveBuffer, sizeof(receiveBuffer), 0);
if (receivedBytes == SOCKET_ERROR)
{
FD_CLR(client->socket, &masterFDSet);
std::cerr << "Error! recv(): " << WSAGetLastError() << std::endl;
closesocket(client->socket);
client->isDisconnected = true;
continue;
You mean 'break'. You got an error. You closed the socket. There is nothing to continue.
}
else if (receivedBytes == 0)
{
FD_CLR(client->socket, &masterFDSet);
std::cout << "Socket " << client->socket << " was closed by the client." << std::endl;
closesocket(client->socket);
client->isDisconnected = true;
continue;
Ditto. You mean 'break'. You got an error. You closed the socket. There is nothing to continue.
}
// Print out the hex value of the incoming data, for debug purposes
const int siz_ar = strlen(receiveBuffer);
Bzzzzzzzzzzzzt. There is no guarantee there is a null anywhere in the buffer. You don't need this variable. The correct value is already present, in receivedBytes.
for (int i = 0; i < siz_ar; i++)
That should be `for (int i = 0; i < receivedBytes; i++)
{
std::cout << std::hex << (int)receiveBuffer[i] << " " << std::dec;
}
std::cout << std::endl;
std::string stringCRLF = "\r\n"; // Carraige return representation
No. That is a carriage return (\r) followed by a line feed (\n), often called CRLF as indeed you have yourself in the variable name. This is the standard line terminator in Telnet.
std::string stringBS = "\b"; // Backspace representation
std::string commandBuffer = receiveBuffer;
Bzzt. This copy should be length-delimited by receivedBytes.
if (commandBuffer.find(stringCRLF) != std::string::npos)
As noted by #DavidShwartz you can't assume you got the CR and the LF in the same buffer.
{
// New line detected. Process message.
ProcessClientMessage(client);
}
else if (commandBuffer.find(stringBS) != std::string::npos)
{
// Backspace detected,
int size = strlen(client->dataBuffer);
client->dataBuffer[size - 1] = '\0';
This doesn't make any sense. You are using strlen() to tell you where the trailing null is, and then you're putting a null there. You also have the problem that there may not be a trailing null. In any case what you should be doing is removing the backspace and the character before it, which requires different code. You're also operating on the wrong data buffer.
}
else
{
// Strip any extra dumb characters that might have found their way in there
commandBuffer.erase(std::remove(commandBuffer.begin(), commandBuffer.end(), '\r'), commandBuffer.end());
commandBuffer.erase(std::remove(commandBuffer.begin(), commandBuffer.end(), '\n'), commandBuffer.end());
// Add the new data to the clients data buffer
strcat_s(client->dataBuffer, sizeof(client->dataBuffer), commandBuffer.c_str());
}

UNIX domain socket C++ server can not return data to client

Here are the simple echo server I'm working on, the server will accept the request from client and return what client sends to it. The program works fine with socat, but will freeze when using my own client.
The problem that my old code has is that I use read instead of read_some. read will block the pipe until it reads certain number of bytes or get a broken pipe exception, whereas read_some will read a chunk at a time. The updated version uses read_some to read input stream and check if the last character the program read is \0, if it is \0, that means it reaches the end of command, so it will echo back. This works because I only pass string literals and there is no binary data in the pipe.
The code of the server is
using namespace std;
const char* epStr = "/tmp/socketDemo";
int main() {
namespace local = boost::asio::local;
boost::asio::io_service io_service;
::unlink(epStr);
local::stream_protocol::endpoint ep(epStr);
local::stream_protocol::acceptor acceptor(io_service, ep);
while(1) {
local::stream_protocol::socket *socket = new local::stream_protocol::socket(io_service);
acceptor.accept(*socket);
char buf[2048] = {0};
boost::system::error_code error;
size_t len = 0;
while(1) {
len += socket->read_some(boost::asio::buffer(buf + len, 2048 - len));
cout << "read " << len << endl;
if (buf[len] == '\0') {
break;
}
}
cout << "read " << len << " bytes" << endl;
cout << buf << endl;
boost::asio::write(*socket, boost::asio::buffer(buf, len), boost::asio::transfer_all());
}
}
When testing the server with socat command, for example
echo "12345" | socat - UNIX-CONNECT:/tmp/socketDemo
it will return the desired result.
My client code is
const char* epStr = "/tmp/socketDemo";
int main(int argc, const char* argv[]) {
boost::asio::io_service io_service;
boost::asio::local::stream_protocol::endpoint ep(epStr);
boost::asio::local::stream_protocol::socket socket(io_service);
socket.connect(ep);
boost::asio::write(socket, boost::asio::buffer(argv[1], strlen(argv[1])), boost::asio::transfer_all());
char buf[1024] = {0};
size_t len = 0;
while(1) {
len += socket.read_some(boost::asio::buffer(buf + len, 2048 - len));
std::cout << "read " << len << std::endl;
if (buf[len] == '\0') {
break;
}
}
std::cout << "read " << len << " bytes\n";
std::cout << buf << std::endl;
socket.close();
When execute the client, at first both have no output, after I killed the client, the server will output that it reads n bytes and get a broken pipe exception.
Can this be caused by the read function in the server? If so is there a way to let it know how much data it should read without sending the size of data chunk at the beginning of each message? I am also wondering why socat can work with this server without any problem? Thanks!
I am also wondering why socat can work with this server without any
problem?
Probably because socat closes the socket and your client doesn't.
If so is there a way to let it know how much data it should read
without sending the size of data chunk at the beginning of each
message?
For instance, reading one byte at a time until you read an end-of-message character, assuming that you're defining / using a protocol that includes EOM.

Why I am always receiving data on the server side of a socket in C++?

After opening a connection between client and server, I need to handle any write command sent to the server using the command read(); (i.e. when the client write(); the server should read(); right away).
It sounds to be a trivial problem. Firstly, I sent 58 bytes from the client. But, I am always receiving huge amount of data on the server side. Here you could find just the relevant part of code:
int sockfd, newsockfd;//, n0,n1,n2;
socklen_t clilen;
struct sockaddr_in serv_addr, cli_addr;
int reuse=1;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
cerr << "ERROR opening socket"<< endl;
if (setsockopt(sockfd, SOL_SOCKET,SO_REUSEADDR,&reuse, sizeof(int)) == -1)
cerr << "ERROR on reusing port"<< endl;
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(iport);
serv_addr.sin_addr.s_addr = INADDR_ANY;
if (bind(sockfd, (struct sockaddr *) &serv_addr,sizeof(serv_addr)) < 0)
cerr << "ERROR on binding"<< endl;
cout << "Listening on port: "<< iport<< endl;
listen(sockfd,1);
clilen = sizeof(cli_addr);
newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
if (newsockfd < 0)
cerr << "ERROR on accept" << endl;
while (1) {
size_t msgSize=0;
int n = read(newsockfd,&msgSize,sizeof(size_t));
cout << "Breakpoint " << msgSize<< endl;
// Reading bytes size from socket until 10MB
if ( n> 0 && msgSize< 10485760) {
byte bytes [msgSize];
if (read(newsockfd, bytes, msgSize) > 0) {
char ip [16];
memset (bytes + msgSize, '\0', MSGMAXSIZE - msgSize - 1);
if (read(newsockfd,ip,15) > 0) {
string cIP = (string)ip;
//cout << "Sender Ip: " << cIP << endl;
process p = currentView.getProcess(cIP);
message m(bytes,p);
cout << "*************************" << endl
<< "Message received:" << endl
<< "*****************" << endl;
m.print();
}
}
}
}
This is the result i got:
Listening on port: 4444
Connected to: 127.0.0.1:6666
Breakpoint 58
*************************
Message received:
*****************
Message text: I am trying to send a message
Message size: 58
Message sender: 127.0.0.1
Message stability: 0
**************************************************
Breakpoint 825634866
Breakpoint 808600630
Breakpoint 842478647
Breakpoint 959854903
Breakpoint 926303542
Breakpoint 876032050
Breakpoint 808601142
Breakpoint 892744503
Breakpoint 875971894
Breakpoint 825634866
Breakpoint 1144401970
Breakpoint 859256118
Breakpoint 825635639
Breakpoint 892745526
Breakpoint 775369265
Breakpoint 774909488
Breakpoint 14897
Segmentation fault
And here you could find the relevant part of code from the client side:
while (1)
{
if (!bufferMsg(m)) break;
}
bool bufferMsg(message m) // Sends a message (m) to a process (p)
{
mtx.lock();
if(fifoBuffer.size() < 5)
{
fifoBuffer.push_back(m);
size_t sizeMsg = m.getHeader().sizeMsg;
byte * bytes = m.getBytes();
if (!write(sendsockfd,&sizeMsg,sizeof(size_t)) || !write(sendsockfd,bytes,sizeMsg) || !write(sendsockfd,(char*)m.getHeader().sender.getIp().c_str(),strlen(m.getHeader().sender.getIp().c_str())))
cerr << "ERROR writing to socket"<< endl;
mtx.unlock();
return true;
}
else{
mtx.unlock();
return false;
}
}
Here you could find the header of the message:
typedef struct HeaderType {
size_t sizeMsg;
process sender; // The header.sender process
//view currentView; // the Current view
//iClock C; // reserved for later use
bool stability; // reserved for later use
}HeaderT;
PS: The terms message and process are some classes which I already created but are out of our concern.
Please feel free should you need more clarification or information.
I have the impression you think that client side write should be blocking and waits until the data is eaten up by the server. The OS is free to deliver as many bytes as it likes on a TCP stream.
You have a lot of if if(read(newsockfd, bytes, msgSize) > 0) in your code where you seem to silently assume that the read either fails completely or delivers exactly the amount of data you're waiting for. That doesn't need to be the case.
This:
if ( n> 0 && msgSize< 10485760) {
byte bytes [msgSize];
is dangerous since the byte array (which I assume is a typedef) gets allocated on the stack and I assume no OS on the planet accepts a 10MB local variable. But I might be wrong or even modern compilers start to silently allocate it on the heap. It's the top candidate for your segfault the first time msgSize <10MB. Better do something like:
std::auto_ptr<byte> bytes(new byte[msgSize]);
For your read in of msgSize better do something like:
int n = 0;
int nn = 0;
while((nn=read(newsockfd,((char *)&msgSize)+n,sizeof(size_t)-n)>0
&& n<sizeof(size_t)) {
n+=nn;
}
On the client site you do something like:
write(sendsockfd,(char*)m.getHeader().sender.getIp().c_str(),strlen(m.getHeader().sender.getIp().c_str())
To transfer something like an IP (I assume a string like 88.1.2.250) But on the server side you read it like:
read(newsockfd,ip,15)
which doesn't need to fit each other. That would lead to a frame shift in your read and the next msgSize is bogus. May I assume the the first msgSize you ever read is correct ? Under the assumption that the first read actually delivers sizeof(size-t).
size_t msgSize=0;
int n = 0;
do{
int t=read(newsockfd,((char*)&msgSize) + n, sizeof(size_t) - n);
if(t<0)
continue; //if no data is available (in nonblocking mode, or on timeout)
if(t==0)
break; //connection closed
n+=t; //increase counter n by the amount actually read
} while(n<sizeof(size_t));
cout << "Breakpoint " << msgSize<< endl;
// Reading msgSize bytes from socket until 10MB
if ( n> 0 && msgSize< 10485760) {
byte bytes [msgSize];
n=0;
int t;
while((t=read(newsockfd, bytes + n, msgSize - n)) > 0 //if something was read
&& (n+=t)<msgSize //and the total is below msgSize, we continue reading
|| t<0) //or when there is no data available, we will give it another attempt
{
}
if(t>0){
cout << "successful: " << n << endl;
} else {
cout << "only " << n << " of " << msgSize << "read" << endl;
}
}
Tricky parts explained:
((char*)&msgSize) + n
This casts the pointer to size_t to a pointer to char and + n increments the pointer by n-times the size of the type it points to.
(t=read(newsockfd, bytes + n, msgSize - n)) > 0
An assignment returns the assigned value. It has to be inside brackets, as without brackets the boolean result of the > comparison would be assigned to t.
Sidenote:
You should not send the raw binary representation of an integer value to another computer. The sender might uses a MSB byte order while the recipient could be using LSB. You should use the methods provided to convert from host byte order to network byte order. They are called htonl and ntohl (h:host, to:to, n:network l:long [4 bytes]).

C++ program freezes during COM port read

I am trying to write a simple program to send single characters to a program via a COM port and read the answers I get back. I think I have working script where I can at least send commands via the com port, but when the ReadFile function begins it freezes. I have the comm timeout set for 100ms, so I don't think that it is locking the port, but I may be wrong. I am not getting any errors, and no warnings when I compile. I am very new to C++ (normally work with python), so please be as clear a possible with your answers.
// comtest.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <iostream>
#include <string>
#include <sstream>
#include <dos.h>
#include <stdio.h>
#include <conio.h>
#include <string.h>
#include <windows.h>
int main(int argc, char **argv)
{
std::cout << "TOP! \n";
char buffer[1];
HANDLE file;
COMMTIMEOUTS timeouts;
DWORD read, written;
DCB port;
char init[] = ""; // e.g., "ATZ" to completely reset a modem.
// open the comm port.
file = CreateFile(L"COM1",
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
0,
NULL);
std::cout << "file made \n";
// get the current DCB, and adjust a few bits to our liking.
memset(&port, 0, sizeof(port));
port.DCBlength = sizeof(port);
// set short timeouts on the comm port.
timeouts.ReadIntervalTimeout = 100;
timeouts.ReadTotalTimeoutMultiplier = 1;
timeouts.ReadTotalTimeoutConstant = 100;
timeouts.WriteTotalTimeoutMultiplier = 1;
timeouts.WriteTotalTimeoutConstant = 100;
int N = 10;
while (N > 1)
{
std::cout << "i'm in the loop!" << N << " loops left \n";
char command [1];
char * commandbuff;
std::cin >> command;
commandbuff = &command[1];
WriteFile(file, commandbuff, sizeof(commandbuff),&written, NULL);
Sleep(1000);
std::cout << "I just slept \n";
ReadFile(file, buffer, sizeof(buffer), &read, NULL);
N--;
}
// close up and go home.
CloseHandle(file);
return 0;
Your code doesn't appear to actually call SetCommTimeouts, so the timeouts you have defined would have no way to be applied.
Receiving data from a com port, don't start reading unless you have first sent a command or something that gets a response. Then, it's preferable to just read one byte at a time, but if you are sending modbus/at commands like I'm doing and know you're expecting 8 bytes back, then it's ok to use readfile to read 8 bytes. Most of the C++ com port examples have SetCommState, SetCommTimeouts, SetCommMask and WaitCommEvent before you can read that single byte.
Mine had an "&" on the second parameter of ReadFile. MS Visual C++ though.
Status = ReadFile(fileusb, &ReadData, sizeof(ReadData), &NoBytesRead, NULL);