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;
}
Related
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
I'm using following code to read from socket:
char buf[4097];
int ret = read(fd, buf, sizeof(buf) - 1);
buf[ret] = 0x0;
std::cout << buf << "\n";
However, I don't like the need for 4097 and sizeof(buf) - 1 in there. It's that kind of stuff that's easy to forget. So I wonder, is there some nice way to force compiler to but 0x0 directly on stack right after the array?
What I would love is something like
char buf[4096];
char _ = 0x0;
int ret = read(fd, buf, sizeof(buf));
buf[ret] = 0x0;
std::cout << buf << "\n";
but I have no idea how to force compiler to not but anything in between (afaik #pragma pack works only on structures, not on stack).
I'd keep things simple:
ssize_t read_and_put_0(int fd, void *buf, size_t count)
{
ssize_t ret = read(fd, buf, count - 1);
if (ret != -1) // Or `if (ret <= 0)`
((char *)buf)[ret] = 0x0;
return ret;
}
// ...
char buf[4097];
read_and_put_0(fd, buf, sizeof buf);
I don't like the need for 4097 and sizeof(buf) - 1 in there
Simplicity is beautiful:
constexpr std::size_t size = 4096;
char buf[size + 1];
int ret = read(fd, buf, size);
buf[ret] = 0x0;
You specify exactly the size that you need, no neet to do manual adding. And there's need for neither sizeof, nor subtracting 1.
Remembering the + 1 for terminator is easier in my opinion than remembering to declare a separate character object - which can't be forced to be directly after the array anyway.
That said, there are less error prone ways to read a text file than read.
The relative location in memory of the values of distinct variables in unspecified. Indeed, some variables might not reside in memory at all. If you want to ensure relative layout of data in memory then use a struct or class. For example:
struct {
char buf[4096];
char term;
} tbuf = { { 0 }, 0 };
int ret = read(fd, tbuf.buf, sizeof(tbuf.buf));
if (ret >= 0 && ret < sizeof(tbuf.buf)) {
tbuf.buf[ret] = '\0';
}
The members of the struct are guaranteed to be laid out in memory in the same order that they are declared, so you can be confident that the fail-safe terminator tbuf.term will follow tbuf.buf. You cannot, however, be confident that there is no padding between. Furthermore, this is just a failsafe. You still need to write the null terminator, as shown, in case there is a short read.
Additionally, even though the representation of tbuf is certain to be larger than its buf member by at least one byte, it still produces UB to access tbuf.buf outside its bounds. Overall, then, I don't think you gain much, if anything, by this.
An alternative to HolyBlackCats answer that doesn't require giving the size argument as long as you have the array and not a pointer to some array.
template <size_t N> ssize_t read_and_put_0(int fd, char (&buf)[N]) {
ssize_t ret = read(fd, buf, N - 1);
if(ret != -1) // Or `if (ret <= 0)`
buf[ret] = 0x0;
return ret;
}
char buf[4097];
read_and_put_0(fd, buf);
I'm developing a server-client application using Winsock in c++ and have a problem.
For getting the message from the client by the server I use the code below.
int result;
char buffer[200];
while (true)
{
result = recv(client, buffer, 200, NULL);
if (result > 0)
cout << "\n\tMessage from client: \n\n\t" << message << ";";
}
I send the message "Hello" from the client to the server. However the buffer is actually this:
HelloÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌ
What am I missing?
Since recv might not receive as many bytes as you told it, you typically use a function
like this to receive specified number of bytes. Modified from here
int receiveall(int s, char *buf, int *len)
{
int total = 0; // how many bytes we've received
int bytesleft = *len; // how many we have left to receive
int n = -1;
while(total < *len) {
n = recv(s, buf+total, bytesleft, 0);
if (n <= 0) { break; }
total += n;
bytesleft -= n;
}
*len = total; // return number actually received here
return (n<=0)?-1:0; // return -1 on failure, 0 on success
}
It's up to you to null terminate the string if you receive string which is not null terminated.
The result tells you how many bytes were received. recv doesn't add a terminator since, in general, network data is binary data which might not be usable as a C-style string.
You can add a terminator yourself, if you know the message won't contain the termination character:
buffer[result] = 0; // make sure the buffer is large enough
or make a string (or vector, or whatever) from it:
std::string message_str(message, result);
Note that what you receive might not be a single "message", especially if you're uses a stream protocol like TCP. It might contain more than one message, or just the start of one.
memset(&receive[0], 0, sizeof(receive));
To clear the buffer
You didn't initialize your buffer
char buffer[200] = {0};
while (true)
{
result = recv(client, buffer, 200, NULL);
if (result > 0)
cout << "\n\tMessage from client: \n\n\t" << message << ";";
memset(buffer, 0, 200);
}
I am reading buffer bytes from a socket but I don't know how to initialize the buffer array with the length info.
uint32_t len;
int lengthbytes = 0;
int databytes = 0;
// receive the length info of an image data
lengthbytes = recv(clientSocket, (char *)&len, sizeof(len), 0);
// convert hexadecimal data to length in bytes
len = ntohl(len);
// ????? how to initialize the buffer array with the length info ????
char buf[len]; -----> this is illegal in C
// read the image data
databytes = recv(clientSocket, buf, sizeof(buf), 0);
len = ntohl(len);
char buf[len]; //----> this is illegal in C
This is valid in C99 and it is called a variable length array. If you are not using C99 use malloc to allocate the array (and declare buf as a char *).
When you declare buf you declare a variable length array. This is legal in C (from the C99 standard) but illegal in C++. In C++ you can instead use std::vector:
std::vector<char> buf(len);
You can use this vector in the call to recv as well:
databytes = recv(clientSocket, &buf[0], buf.size(), 0);
To use the vector inside a loop, you have two choices:
Declare the variable outside the loop, and use clear and resize when needed:
std::vector<char> buf;
// ...
for (int i = 0; i < number_of_images; i++)
{
std::cout << "Fetching image #" << (i + 1) << '\n';
// Get the image length
size_t length = get_image_length();
buf.clear(); // Clear the buffer
buf.resize(length); // Set the size to the image length
// Receive the image
databytes = recv(clientSocket, &buf[0], buf.size(), 0);
}
Declare the vector to be local inside the loop:
for (int i = 0; i < number_of_images; i++)
{
std::cout << "Fetching image #" << (i + 1) << '\n';
// Get the image length
size_t length = get_image_length();
std::vector<char> buf(length);
// Receive the image
databytes = recv(clientSocket, &buf[0], buf.size(), 0);
}
You have to use dynamic memory allocation;
char* buf = new char[len];
If you're done using buf, don't forget to call delete to free the memory.
delete[] buf;
Please allocate the buffer through malloc i.e. buf = malloc(sizeof(char) * len);
You can do it with new or malloc.
Don't forget to delete the buffer when done!
You can use an std::vector<char>, and then use it's data() as an array buffer:
#include <vector>
std::vector<char> buf(len);
databytes = recv(clientSocket, buf.data(), buf.size(), 0); // access underlying char array
databytes = recv(clientSocket, &buf[0], buf.size(), 0); // as above, C++03 version
I wrote a class called tempbuf precisely for this purpose in C++.
You can find it here:
small_lib.cpp
small_lib.h
These two files are MIT-licensed, so you can use it anyway you like.
How to use this class?
tempbuf buf(len);
databytes = recv(clientSocket, buf.get(), buf.size(), 0); // if you want char* returned
databytes = recv(clientSocket, buf.constchar(), buf.size(), 0); // if you want constchar* returned
And guess why I wrote this class? You don't need to delete or deallocate the dynamically allocated memory because it is done in the destructor of the class.
Why didn't I use std::auto_ptr? Because from my understanding, that's only for non-arrays as in it supports new X but not new X[10].
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.
}