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.
}
Related
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());
}
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;
}
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);
}
Hi please some one help me
I've two process say some X and Y.
X and Y both have the following information
typedef enum {
HEALTHY=1,
FAULTY=2,
CHANGE=3,
ERROR=4
} MsgTypeT;
typedef struct {
char role[16];
char state[16];
char info[256];
} InfoT;
typedef struct {
MsgTypeT type;
int size;
InfoT *data;
} MsgT;
Here the condition is that if process Y sends an information process X will read it
So i used fifo between x and y
Y has a function write buffer which writes to fifo and code is as following
int write_buffer(HA_DEVMON_MsgT const* send)
{
char* dest = buffer;
memcpy( dest, &send->type, sizeof( MsgTypeT ));
dest += sizeof(MsgTypeT);
memcpy( dest, &send->size, sizeof( int ));
dest += sizeof(int);
memcpy( dest, send->data, sizeof( InfoT ));
dest += sizeof(InfoT);
int byteCount = write( this->fifo_fd, buffer, dest - buffer );
if ( byteCount != dest - buffer ) {
cout<<"Error in writing ";
}
return byteCount == dest - buffer ? 0 : -1;
}
I think it's writing perfectly because cout statements are working fine also when tried to output nbytes it gave 512bytes have been written
Now when X tries to read it's giving null values for role and state also size its giving 6441568
Its only giving MsgTypeT correct other values are null :(
The code is as follows--- I'm doing something wrong please correct it
int readMsg(MsgT *msg)
{
int rCode=0, nbytes=0;
char buffer[512]={0};
nbytes = read(this->get_handle(), buffer, sizeof(buffer));
if (nbytes < 0) {
cout<<"error in read";
rCode=-1;
}
if (rCode == 0) {
char *p_src = (char *)buffer;
mempcpy(&msg->type, p_src, sizeof(MsgTypeT));
p_src+=sizeof(MsgTypeT);
mempcpy(&msg->size, p_src, sizeof(int));
p_src+=sizeof(int);
msg->data = new InfoT(); //allocating memory (needed or not???)
mempcpy(msg->data, p_src, sizeof(InfoT));
p_src+=sizeof(InfoT);
}
return rCode;
}
In readMsg, your last mempcpy writes to msg, not to the
InfotT you just allocated.
Also, but I suppose you know this: this is only guaranteed to
work if both processes were compiled with the same compiler,
using the same options. (In practice, it's likely to work if
the underlying system defines its API in terms of C, which is
the case for Windows and Unix.)
EDIT:
Further: you have the same problem when writing. You write
sizeof(InfoT) (288) bytes, but you write the pointer (and then
a lot of garbage), not the data it's pointing to.
And you increment the pointer into the MsgT object. This is
likely not to work, if there is any padding. What you really
have to do is:
int
write_buffer( MsgT const* data )
{
char buffer[512] = {}; // Or better yet, std::vector<char>
char* dest = buffer;
memcpy( dest, &data->type, sizeof( MsgTypeT ) );
dest += sizeof( MsgTypeT );
memcpy( dest, &data->size, sizeof( int ) );
dest += sizeof( int );
memcpy( dest, &data->data, sizeof( InfoT ) );
dest += sizeof( InfoT );
int byteCount = write( fifo_fd, buffer, dest - buffer );
if ( byteCount != dest - buffer ) {
std::cerr << "Error in write" << std::endl;
}
return byteCount == dest - buffer ? 0 : -1;
}
and the opposite when reading.
And once again, this will only really work for two processes on
the same machine, compiled with the same compiler using the same
options. A better solution would probably be to define
a protocol, with a defined representation of integers, strings,
etc., format your output to that representation, and parse it
for your input. That way, it will still work even if one of the
processes is 64 bits, and the other 32.
I have written a read function which reads values from serial port(LINUX) . It returns values as pointer to char . I am calling this function in another function and storing it again in a variable as pointer to char . I occasionally got stack over flow problem and not sure if this function is creating problem.
The sample is provided below. Please give some suggestions or criticism .
char *ReadToSerialPort( )
{
const int buffer_size = 1024;
char *buffer = (char *)malloc(buffer_size);
char *bufptr = buffer;
size_t iIn;
int iMax = buffer+buffer_size-bufptr;
if ( fd < 1 )
{
printf( "port is not open\n" );
// return -1;
}
iIn = read( fd, bufptr, iMax-1 );
if ( iIn < 0 )
{
if ( errno == EAGAIN )
{
printf( "The errror in READ" );
return 0; // assume that command generated no response
}
else
printf( "read error %d %s\n", errno, strerror(errno) );
}
else
{
// *bufptr = '\0';
bufptr[(int)iIn<iMax?iIn:iMax] = '\0';
if(bufptr != buffer)
return bufptr;
}
free(buffer);
return 0;
} // end ReadAdrPort
int ParseFunction(void)
{
// some other code
char *sResult;
if( ( sResult = ReadToSerialPort()) >= 0)
{
printf("Response is %s\n", sResult);
// code to store char in string and put into db .
}
}
Thanks and regards,
SamPrat
You do not deallocate the buffer. You need to make free after you finished working with it.
char * getData()
{
char *buf = (char *)malloc(255);
// Fill buffer
return buf;
}
void anotherFunc()
{
char *data = getData();
// Process data
free(data);
}
In your case I think you should free the buffer after printf:
if( ( sResult = ReadToSerialPort()) >= 0)
{
printf("Response is %s\n", sResult);
// code to store char in string and put into db .
free(sResult);
}
UPDATE Static buffer
Another option to use static buffers. It could increase performance a little bit, but getData method will be not a thread-safe.
char buff[1024];
char *getData()
{
// Write data to buff
return buff;
}
int main()
{
char *data = getData();
printf("%s", data);
}
UPDATE Some notes about your code
int iMax = buffer+buffer_size-bufptr; - iMax will always be 1024;
I do not see any idea of using bufptr since its value is the same as buffer and you do not change it anywhere in your function;
iIn = read( fd, bufptr, buffer_size-1 );
You can replace bufptr[(int)iIn<iMax?iIn:iMax] = '\0'; with bufptr[iIn] = '\0';
if(bufptr != buffer) is always false and this is why your pointer is incorrect and you always return 0;
Do not forget to free the buffer if errno == EAGAIN is true. Currently you just return 0 without free(buffer).
Good luck ;)
Elalfer is partially correct. You do free() your buffer, but not in every case.
For example, when you reach if ( errno == EAGAIN ) and it evaluates to true, you return without doing free on your buffer.
The best would be to pass the buffer as a parameter and make it obvious that the user must free the buffer, outside the function. (this is what basically Elalfer sais in his edited answer).
Just realized this is a C question, I blame SO filtering for this :D sorry! Disregard the following, I'm leaving it so that comments still make sense.
The correct solution should use std::vector<char>, that way the destructor handles memory deallocation for you at the end of scope.
what is the purpose of the second pointer?
char *buffer = (char *)malloc(buffer_size);
char *bufptr = buffer;
what is the purpose of this?
int iMax = buffer+buffer_size-bufptr; // eh?
What is the purpose of this?
bufptr[(int)iIn<iMax?iIn:iMax] = '\0'; // so you pass in 1023 (iMax - 1), it reads 1023, you've effectively corrupted the last byte.
I would start over, consider using std::vector<char>, something like:
std::vector<char> buffer(1500); // default constructs 1500 chars
int iRead = read(fd, &buffer[0], 1500);
// resize the buffer if valid
if (iRead > 0)
buffer.resize(iRead); // this logically trims the buffer so that the iterators begin/end are correct.
return buffer;
Then in your calling function, use the vector<char> and if you need a string, construct one from this: std::string foo(vect.begin(), vect.end()); etc.
When you are setting the null terminator "bufptr[(int)iIn
bufptr[iMax]=>bufptr[1024]=>one byte beyond your allocation since arrays start at 0.
Also int this case "int iMax = buffer+buffer_size-bufptr;" can be re-written as iMax = buffer_size. It makes the code less readable.