Convert double to char array without padding in c++ - c++

I am trying to send a double through a UDP winsock using the Sendto function but first I need to convert it to a char[]. After trying multiple approaches, the best thing I came up with is the following:
// send
memset(buf, '\0', BUFLEN);
double a = position.y();
char arr[sizeof(a)];
cout << "double" << a << endl;
ToString(arr, sizeof(a), a);
sendto(s, arr, strlen(arr), 0, (struct sockaddr *) &si_other, slen);
cout << "Send" << arr << endl;
This unfortunately gives out a weird trailing padding that ruins the send operation. Any ideas on how to solve this?
My ToString function is the following:
void ToString(char * outStr, int length, double val)
{
_snprintf(outStr, length, "%f", val);
}
The output looks like this:
double 0.003
Send 0.003(a bunch of gibberish)

You are assuming that the number of bytes that the binary double occupies is the same length as the converted string occupies but that is unlikely.
If you have C++11 you can do something like this:
void send_double(int s, sockaddr* si_other, int slen, double d)
{
auto buf = std::to_string(d);
sendto(s, buf.data(), buf.size(), 0, si_other, slen);
}
Otherwise you can do something like this:
void send_double(int s, sockaddr* si_other, int slen, double d)
{
std::ostringstream oss;
oss << d;
std::string buf = oss.str();
sendto(s, buf.data(), buf.size(), 0, si_other, slen);
}
See std::string, std::to_string and std::ostringstream

Related

std::vector buffer throwing bad_alloc in TCP socket code

I am trying to send and receive a string using a TCP socket. I found some code online and modified it. Here is my sendString and receiveString code:
static inline void sendString(int socket, std::string s) {
size_t size = s.size();
size_t size_size = sizeof(size_t); // We make our buffer:
std::vector<char> buffer(size + size_size); // Put the size at the front:
char* size_begin = reinterpret_cast<char*>(&size);
std::copy(size_begin, size_begin + size_size, &(buffer[0])); // Copy the string data:
std::copy(s.begin(), s.end(), &(buffer[size_size])); // And finally send it:
send(socket, &buffer, size + size_size, 0);
}
std::string receiveString(int socket) {
size_t size_size = sizeof(size_t);
size_t size; // We read the size:
recv(socket, (char*)&size, size_size, 0);
std::vector<char> buffer(size); /** XXX: BAD ALLOC*/
recv(socket, &buffer[0], size, 0);
return std::string(buffer.begin(), buffer.end());
}
When I try to have my client send an actual string, the server side throws a std::bad_alloc in receiveString where indicated by a comment. Why did similar code work in sendString but not in receiveString? What is causing the bad::alloc issues? Also, would my code work for sending and receiving a string over a TCP socket?
Thanks!
In sendString(), you are not passing the prepared vector content to send() correctly. You need to change &buffer to either &(buffer[0]) or buffer.data() instead.
That being said, the vectors are completely unnecessary in sendString() and recvString(). Just call send()/recv() multiple times, you can send/receive the size_t and string separately, and let the socket handle the buffering of bytes for you.
For that matter, send() and recv() are not guaranteed to actually send/receive the requested buffer in one go. You have to pay attention to their return values, calling them in loops until all bytes have actually been sent/received.
Also, you are not taking into account that different platforms have different sizes and endians for multi-byte integers. So you need to handle that better, too.
Try something more like this:
static inline void sendRaw(int socket, const void *buffer, size_t bufsize) {
const char *ptr = static_cast<const char*>(buffer);
while (bufsize > 0) {
int numSent = send(socket, ptr, bufsize, 0);
if (numSent < 0)
throw std::runtime_error("send failed");
ptr += numSent;
bufsize -= numSent;
}
}
static inline void sendUint32(int socket, uint32_t value) {
value = htonl(value);
sendRaw(socket, &value, sizeof(value));
}
static inline void sendString(int socket, const std::string &s) {
size_t size = s.size();
if (size > std::numeric_limits<uint32_t>::max())
throw std::runtime_error("string is too long in length");
sendUint32(socket, static_cast<uint32_t>(size));
sendRaw(socket, s.c_str(), size);
}
static inline void recvRaw(int socket, void *buffer, size_t bufsize) {
char *ptr = static_cast<char*>(buffer);
while (bufsize > 0) {
int numRecv = recv(socket, ptr, bufsize, 0);
if (numRecv < 0) throw std::runtime_error("recv failed");
if (numRecv == 0) throw std::runtime_error("peer disconnected");
ptr += numRecv;
bufsize -= numRecv;
}
}
static inline uint32_t recvUint32(int socket) {
uint32_t value;
recvRaw(socket, &value, sizeof(value));
return ntohl(value);
}
std::string receiveString(int socket) {
uint32_t size = recvUint32(socket);
std::string s;
if (size > 0) {
s.resize(size);
recvRaw(socket, &s[0], size);
}
return s;
}
std::bad_alloc is thrown when the system can't allocate the requested memory. Most likely - the size is too big.
My crystal ball tells me that you may witness an issue with endianness. I would convert host-to-network going up, and network-to-host on receive.
UPDATE:
As was pointed in multiple comments, if your call to recv() fails, the size will contain uninitialized garbage. You need to do two things to avoid that: initialize size with 0 AND check if recv() succeeded

Send big string into socket

I'm new with C++ and came to this problem. I'm trying to send big string to a socket. I've seen the similar questions on stack but could not found the real answer. For example these:
Sending a long String over a Socket C++
Send a string with sockets in C++ (Winsock TCP/IP)
C++ sending string over socket
Most of them rely on fact that send would send the whole data in one call, or they would use char * instead of std::string.
Here is little code written in C:
int SendAll(SOCKET client_socket, const void *data, int data_size)
{
const char *data_ptr = (const char*) data;
int bytes_sent;
while (data_size > 0)
{
bytes_sent = send(client_socket, data__ptr, data_size, 0);
if (bytes_sent == SOCKET_ERROR)
return -1;
data_ptr += bytes_sent;
data_size -= bytes_sent;
}
return 1;
}
and now imagine that instead of const void *data we have std::string data. The question is how can I move pointer into data like this data_ptr += bytes_sent; with std::string?
One way that I came out is to retrieve the row pointer of std::stirng save it in some const char * var then use that variable in the same way(var += bytes_sent). But as I'm new with C++ I don't know if it's the "C++ way" of doing this? Is this the best solution to this problem or is there better one? thanks
Yes, that is the best way.
You have to obtain a pointer to the data anyway, to use send, so just adjust the pointer as you see fit.
Something like:
int SendAll(SOCKET client_socket, const std::string& str)
{
const char* data_ptr = str.data();
std::size_t data_size = str.size();
int bytes_sent;
while (data_size > 0)
{
bytes_sent = send(client_socket, data_ptr, data_size, 0);
if (bytes_sent == SOCKET_ERROR)
return -1;
data_ptr += bytes_sent;
data_size -= bytes_sent;
}
return 1;
}
This is perfectly fine and idiomatic.
If you want to keep both versions of the function, just forward the string's buffer to your existing overload:
int SendAll(SOCKET client_socket, const std::string& str)
{
return SendAll(
client_socket,
reinterpret_cast<const void*>(str.data()),
str.size()
);
}
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
This is the signature of send. It requires a pointer to the buffer. Although a C++ API would probably prefer a pair of iterators, rather than a pointer and a size, this is not really possible here, seeing that the pointer to the actual buffer is required. So, there's nothing you can do about it, really. You can just use the string's data() member function to get a poninter to the start of the buffer, and work with that. This should be perfectly fine.
As suggested by Some programmer dude in the comments, you could add a simple overload that facilitates this:
int SendAll(SOCKET client_socket, std::string const& str) {
return SendAll(client_socket, reinterpret_cast<const void*>(str.data()), str.size());
}

C++ Help about ZeroMemory

I defined my char as usual, although I named it buf. I keep getting an error:
argument of type 'char' is incompatible with parameter of type 'void*'
If I set buf to void*, it won't be able to pass in 4096 as a parameter.
So, how do I get around this? Has anyone run into a problem like this before?
char buf{4096};
string userinput;
do
{
cout << "> " << endl;
getline(cin, userinput);
if (userinput.size() > 0) // make sure the user typed something in
{
int SendResult = send(sock, userinput.c_str, userinput.size() + 1, 0);
if (SendResult != SOCKET_ERROR)
{
ZeroMemory(buf, 4096);
int bytesReceived = recv(sock, buf, 4096, 0);
if (bytesReceived > 0)
{
cout << "SERVER" << string(buf, 0, bytesReceived) <<
endl;
}
}
}
The problem is likely this definition:
char buf{4096};
Which is roughly equivalent to:
char buf = 4096;
Which is a single character, not a character array buffer. To fix this:
char buf[4096];
When passing that in you may need to do:
ZeroMemory(&buf, 4096);
I'd strongly encourage you to avoid hammering out 4096 everywhere, so define a constant:
const SIZE_T buf_size = 4096;
char buf[buf_size];
// ...
ZeroMemory(&buf, buf_size);
How about:
#include <array>
std::array<char, 4096> buf;
...
std::fill(buf.begin(), buf.end(), 0);
int bytesReceived = recv(sock, buf.data(), buff.size(), 0);
...
Another question is why do you need ZeroMemory at all. And I think what happened here is that you picked up wrong string constructor overload. Let me explain:
You have your buf buffer and you have your bytesReceived length of data, so really all you need is
std::string(buf, bytesReceived)
to construct valid string. But you have chosen
std::string(buf, 0, bytesReceived)
This overload looks like this:
basic_string( const basic_string& other,
size_type pos,
size_type count,
..
The buf is implicitly converted into std::string at the 1st argument, but for this to work correctly your buffer needs to be null terminated, which it might or might not be. So you worked around this problem by zeroing the rest of the buffer. What do you think will happen if you get 4096 bytes of data that is not null terminated? Your workaround will not work in this case. So just use the appropriate string constructor mentioned above and you won't need to use ZeroMemory.
Use char buf[4096]; instead of buf{4096}
use buf as an array then Fill the block of memory with zeros
by the way, do you really know what does buf{4096} do??
if you do that it means that you want to put this number 4096
which will be converted to "(`" because the buf data type is char so you have used wrong way.
ZeroMemory(buf, 4096);
// Wait for client to send data
int bytesReceived = recv(clientSocket, buf, 4096, 0);
if (bytesReceived == SOCKET_ERROR)
{
cerr << "Error in recv(). Quitting" << endl;
break;
}

Why does the console cout some wrong letters after memcpy of a char*

I copy a char* to a char* and get it back and coutit.
char buffer[100] = { 0 };
char* name = "foo";
int bar = 12345;
memcpy(buffer, &(bar), 4);
memcpy(buffer + 4, name, 3);
int result = 0;
memcpy(&result, buffer, 4);
char backname[3];
memcpy(backname, buffer + 4, 3);
std::cout << result << std::endl;
std::cout << backname << std::endl;
Why does it show this:
12345
foo╠╠╠╠╠╠╠╠╠90
but strcmp(backname,"foo")does let me know that they match?
Edit:
Things I would fix:
Use sizeof(int) instead of 4. This is most likely not the real issue.
backname is not a null-terminated string the way you are using it. Use:
char backname[4] = {0};
memcpy(backname, buffer + sizeof(int), 3);

Passing Array into function that sends UDP packet

I am using Winsock2 sockets to transfer some data over UDP. I am having difficulties passing the array into the sendTo() function to send the data.
I have wrote a mySocket class for future reuse and I have the following method currently, which works.
bool MySocket::sendData()
{
short int values[] = {1000,2000,3000,4000,5000};
int ret = sendto( sd,(const char*)values, sizeof(values) , 0, (sockaddr *)&sin, sizeof(sin) );
if(ret == SOCKET_ERROR)
{
return false;
}
return true;
}
Now I want to pass in a array instead of having
short int values[] = {1000,2000,3000,4000,5000};
So the new function would look like:
bool MySocket::sendData(short int data[])
{
short int * values = data;
int ret = sendto( sd,(const char*)&values, sizeof(data) , 0, (sockaddr *)&sin, sizeof(sin) );
if(ret == SOCKET_ERROR)
{
return false;
}
return true;
}
When the function is called the call would be:
short int data[] = {1000,2000,3000,4000,5000}; //Or some other pre-assembled list of short ints
if(socket->sendData(data))
cout << "Server: Packet Sent" << endl;
else
cout << "Server_Error: Packet failed to send" << endl;
I seem to just be getting the address of the pointer for data or values. I have been playing around with the "&" and pointers, but haven't found the correct way to transfer anything but the first number, which is where the pointer is pointing. I mostly write code in C# and switching back to C++ now has left my pointer skills pretty rusty.
How would I pass or use the passed in array to send it correctly?
What MySocket::sendData is getting should be a pointer to the data, not the address of the pointer. sizeof will not be the right way to check for the number of elements. Indeed, that will be the sizeof a pointer as you are saying. Also, you should be passing (const char *)values to sendto. That will do. To calculate the number of bytes to send, multiply the number of elements by sizeof(short). So I would suggest you pass the number of elements as an additional argument to MySocket::sendData. It will look like this:
bool MySocket::sendData(short int data[], int n_data)
{
int ret = sendto(sd, (const char*)values, n_data * sizeof(short) , 0, (sockaddr *)& sin, sizeof(sin));
if(ret == SOCKET_ERROR)
{
return false;
}
return true;
}
You need to explicitly pass size of the data array to your sending function. This is one of the subtleties of C and C++ - array type is decayed to a pointer when passed as function argument, so you lose array size information. Just do something like this:
bool sendInts( short* data, size_t count ) {
int rc = ::send( data, count * sizeof( short ), ... );
// handle errors etc.
}
Or even better, take an std::vector<short> by reference:
bool sendInts( const std::vector<short>& data ) {
assert( data.size() > 0 );
int rc = ::send( &data[0], data.size() * sizeof( short ), ... );
// handle errors etc.
}