I'm trying to send arrays trough the net with winsock2. Now, i read microsoft disabled sending raw pointers, but you can still send un-edited binary data by casting the pointer to char*:
send(rsock, (char*)&counter, len, 0);
However, the problem is putting the data back in an array when it reaches the client. here, pass is the binary data. That's how I do fot integers, bools and doubles.
recv(sock, pass, sizeof(int), 0);
refresh = (int((void*)&pass));
recv(sock, pass, sizeof(bool[4800][254]), 0);
**key = (bool)&pass;
recv(sock, pass, sizeof(double[4800][254]), 0);
**mil = (double)&pass;
Integers aren't arrays, while bool and doubles are stored in 2 dimensional arrays. Now, the compiler says this code works for int and bool but for doubles it says "'type cast' : cannot convert from 'char **' to 'double'"
"invalid type conversion" even though I'm trying to put raw data in it. Have I done something wrong? Is there any other workaround to send arrays? Thanks in advance.
EDIT: also, I still haven't tried the code with another PC, so I highly doubt the conversion for ints and bools is done right.
Microsoft didn't disable sending anything. The fact is that sending a pointer will simply be of no use to the remote peer. A pointer is simply a memory address, and it is useless to know the address if the information is not there.
The problem you are probably facing is that this array is too big to fit the send buffer, that by default can hold only 64KB.
Pay attention to the return values of send() and recv() to know how much data you actually read/sent in that transaction. It will not always be the same size you told the function to do, as it is often split in pieces smaller than 4KB. You will have to manage the transmission of this information in pieces to fill your entire array.
Have I done something wrong?
Well...
by default, send and recv don't guarantee to return only after all the buffer you've supplied is either sent or received; they may return as soon as they've enqueued a bit more data for sending, or after receipt of a bit more data that you might be able to process... the buffer size supplied is just an upper limit to your request, not a minimum. If you want to ensure recv doesn't return until the full buffer has been populated, add the MSG_WAITALL flag as a final parameter. For send you must loop sending further parts of your output buffer.
check you return codes... send and recv tell you of errors and have pretty little numbers that give you clues as to the cause and resolution
"the compiler says this code works" - no it doesn't... it says your code requests something it's prepared to compile, full of casts that it isn't meant to try to verify, most of which will crash at runtime
Then there's this:
recv(sock, pass, sizeof(int), 0);
refresh = (int((void*)&pass));
recv(sock, pass, sizeof(bool[4800][254]), 0);
**key = (bool)&pass;
recv(sock, pass, sizeof(double[4800][254]), 0);
**mil = (double)&pass;
I'm not even going to begin to say what's wrong with all that... let's just talk about what might work (might being discussed below):
template <typename T>
void get(int sock, T& t)
{
if (recv(sock, (char*)&t, sizeof t, MSG_WAITALL) != sizeof t)
throw std::runtime_error("error while reading data from socket");
}
int refresh;
get(refresh);
bool key[4800][254];
get(key);
double mil[4800][254];
get(mil);
If your sending and receiving systems, compilers, compiler flags, executables etc. differ in any way then this may not work anyway as:
up until C++03 compilers weren't required to use any particular type to store bool, so who knows if your sending and receiving side will match
big and little endian systems have different byte ordering which can break naive binary transfers like this
the size of int may vary
Ultimately, a more robust way to do this would be to use the boost serialisation library.
Related
When using Berkeley socket api, what is the data type of content that is sent over the read/send or write/recv calls? For example -
char *msg = "Our Message!";
int len, bytes_sent;
len = strlen(msg);
bytes_sent = send(sockfd, msg, len, 0);
in this code, we are using char type, but are we limited to just char type since send/write/sendto usually take void * type. I've also seen arguments like if we send some int, it might actually be stored in little endian/big endian causing problems b/w source/dest if their endianess don't match. Then why doesn't char type suffers from this problem too?
Also different languages like C and C++ have different size of char too, then why isn't this a problem? If socket doesn't care any type and just sees the content as buffer, why don't we see random corruption of data when different tcp servers/clients are written in different languages and communicate with each other?
In short, what values(type) can I send safely through sockets?
You cannot safely send anything through a raw socket and expect the receiver to make sense of it. For example, the sending process might be on a machine where the character encoding is EBCDIC, and the receiving process might be on a machine where the character encoding was ASCII. It's up to the processes to either negotiate a protocol to sort this out, or to simply say in their specifications "We are using ASCII (or whatever)".
Once you have got the character encodings worked out, transmit the data in text is my advice. This avoids all endian problems, and is easier to debug and log.
The simplest answer is that the data is an uninterpreted stream of octets, that is to say 8-bit bytes. Any interepretation of it is done by the sender and receiver, and they better agree. You certainly need to take both the size and endianness of integers into account, and compiler alignment and padding rules too. This is why for example you should not use C structs as network protocols.
I have a char pointer & have used malloc like
char *message;
message=(char *)malloc(4000*sizeof(char));
later I'm receiving data from socket in message what happens if data exceeds 4000 bytes ?
I'll assume you are asking what will happen if you do something like this:
recv(socket,message,5000,0);
and the amount of data read is greater than 4000.
This will be undefined behavior, so you need to make sure that it can't happen. Whenever you read from a socket, you should be able to specify the maximum number of characters to read.
Your question leaves out many details about the network protocol, see the answer by #DavidSchwartz.
But focussing on the buffer in which you store it: if you try to write more than 4K chars into the memory allocated by message, your program could crash.
If you test for the size of the message being received, you could do realloc:
int buf_len = 4000;
char *message;
message = static_cast<char*>(malloc(buf_len));
/* read message, and after you have read 4000 chars, do */
buf_len *= 2;
message = static_cast<char*>(realloc(message, buf_len));
/* rinse and repeat if buffer is still too small */
free(message); // don't forget to clean-up
But this is very labor-intensive. Just use a std::string
int buf_len = 4000;
std::string message;
message.reserve(buf_len); // allocate 4K to save on repeated allocations
/* read message, std::string will automatically expand, no worries! */
// destructor will automatically clean-up!
It depends on a few factors. Assuming there's no bug in your code, it will depend on the protocol you're using.
If TCP, you will never get more bytes than you asked for. You'll get more of the data the next time you call the receive function.
If UDP, you may get truncation, you may get an error (like MSG_TRUNC). This depends on the specifics of your platform and how you're invoking a receive function. I know of no platform that will save part of a datagram for your next invocation of a receive function.
Of course, if there's a bug in your code and you actually overflow the buffer, very bad things can happen. So make sure you pass only sane values to whatever receive function you're using.
For the best result,you get a segmentation fault error
see
What is a segmentation fault?
dangers of heap overflows?
According to the protocol-buffers api, ParseFromArray(const void * data, int size) will fail if the format is wrong, in my case, it return false when the size parameter is not right. A lot of answers point out that ByteSize() should be used when using SerializeToArray(void * data, int size),and make sure parse the right size, but none of them clearly point out how. So how to pass the ByteSize() value to the server side to make sure ParseFromArray doesn't return false?
As far as I know, all the examples I found make the size parameter the full size of a receive buffer, and didn't check the return value at all, since the fields will parse any way. Is this a good idea leaving the return value unchecked?
Is this a good idea leaving the return value unchecked?
No!
Where did you get the buffer of data from? Wherever you got it, should have also told you how many bytes are in the buffer.
For example, if you used recv() to receive a UDP datagram from the network, it returns the number of bytes received.
If you are using TCP, then again recv() returns the number of bytes received, but note that the message may arrive in multiple parts. You need some way to know when it is done, such as by using shutdown() to end the stream after the message is sent, or by separately writing the size before the message. For the latter solution, you might be interested in my pull request, which adds helpers to protobufs to accomplish this (but it's not too hard to do yourself, too).
I have a client/server program I'm writing, I need to send information from client to server using the function send(SOCKET s, const char *buf, int len, int flags);
but apparently this function is made to said a string, array of characters, but what I'm sending is encrypter message and the characters values large and character type isn't enough.
is there another function that allows me to do so ? I looked the reference in microsoft website but I didn't get the other functions.
if there's another function I hope you can show me how or give me hints, or if there's another way to do then so be it.
Notes: I'm working with C++ under Windows 8, using Borland 6
This might be tricky to explain.
Your issue isn't in the function you're using, but in the concept you're trying to apply.
First of all, if your data is intended to be transmitted through network, you must assume that the destination endpoint endianness may differ from the transmitting endpoint.
With that in mind, it's advisable to convert the eligible data types prone to endianness interpretation to network byte order before transmitting any data. Take a look at the htons(), htonl(), ntohs() and ntohl() functions.
As you must deal with known data sizes, instead of declaring your array as int[], you should declare it through a stdint.h type, such as int16_t, int32_t, uint16_t, etc.
So, lets assume you've the following:
uint32_t a[4] = { 1, 2, 3, 4 };
If you want to transmit this array in a portable way, you should first convert its contents to network byte order:
uint32_t a_converted[4];
for (int i = 0; i < sizeof(a); i ++)
a_converted[i] = htonl(a[i]);
Now, if you want to transmit this array, you can do it using:
send(s, (char *) a_converted, sizeof(a_converted), flags);
Just remember that the code for receiving this data, should convert it from network byte order to host byte order, using, in this case, the ntohl() for each element received.
Hope this gives you some clues for further research.
Well doodleboodle, guess what, if you read the TCP RFC, you might under stand that the TCP protocol only transfers OCTET STREAMS and, if you need to transfer anything more complex than one byte, you need a protocol on top of TCP that defines your Application Protocol Unit message type.
send(SOCKET s, const char *buf, int len, int flags); is basically the way to do it.
It uses binary data in bytes to send the data. So if you want to send a complex structure/object, you'll need to serialize it to a byte array first.
In your case with the integers it's quite simple: just convert the integer array to a byte array. (keep track of the length though).
Of course it's more appropriate to build an abstraction layer on top of your TCP layer so it's easier to send/receive different kinds of data.
I have a server and a client. I am using winsock2. The client sends 4 bytes:
char *ack = new char[4];
sprintf( ack, "%d", counter );
sendto( clientSocket, ack, 4, 0, ( struct sockaddr* )&remote, sizeof( remote ) );
and the server receives these 4 bytes:
char* acks = new char[4];
if( ( bytes = recvfrom( serverSocket, acks, 4, 0, ( struct sockaddr* )&remote, &remote_size ) ) == SOCKET_ERROR ) {
cout << "socket error = " << WSAGetLastError() << endl;
break;
}
if( bytes > 0 ) {
sscanf( acks, "%d", &i );
}
I am getting this error and I can't figure out how to fix it:
>Critical error detected c0000374
>
>server.exe has triggered a breakpoint.
I know there is a problem with the pointer and the memory allocation. But my c++ skills are basic.
String formatting overflow
The most pressing issue is that you are using sprintf and sscanf. Avoid using sprintf and sscanf - they make it far too easy to accidentally create the type of bug you're seeing here, which is buffer overflow (on both your client and your server).
Consider what happens on your client when your 'counter' value is 1729. Your code will run
sprintf(ack, "%d", 1729);
The C-style-string representation of 1729 is five bytes long - one byte each for the char values '1', '7', '2', '9', and '\0'. But your ack buffer is only 4 bytes long! Now you've written that last zero byte into some chunk of memory you never allocated. In C/C++, this is undefined behavior, which means your program might crash, or it might not, and if it doesn't crash, it might end up subtly wrong later, or it might work perfectly well, or it might work most of the time except it breaks on Tuesdays.
It's not a good place to be.
You might be wondering, "if this is so awful, why didn't the sprintf just return an error or something I called it with a buffer that was too small?" The answer1 is that sprintf can't make that check because it doesn't give you any way to tell it how big ack actually is. When your code here is calling sprintf, you know that ack is 4 bytes long (since you just created it), but all sprintf sees is a pointer to some memory, somewhere - you haven't told it a length, so it just has to blindly hope the chunk of memory you give it is big enough.
Blindly hoping is a pretty bad way to write software.
There's a few alternatives you could consider here.
If you are actually just trying to send an int across the wire, there's not really any need to stringify the int at all - just send it in its native format by passing reinterpret_cast<char*>(&counter) as your buffer to sendto2 with sizeof(counter) as the corresponding buffer length. Use a similar construction in recvfrom on the other end. Note that this will break if your sender and your receiver have different underlying representations of ints (for example, if they use different endiannesses), but since you're talking about Winsock here I'm assuming you're assuming both ends are reasonably recent versions of Windows where that won't be a problem.
If you really do need to stringify the content first, use size-cognizant string conversion functions, like boost::format (which is implicitly size-cognizant because it deals in std::string instead of raw char* buffers) or _snprintf_s/_snscanf_s (which explicitly take in buffer length parameters, but are Microsoft-specific).
Recvfrom access violation
The overflow in sscanf/sprintf doesn't necessarily explain this, however:
I just want to add that the error occurs in the sscanf line. If I comment that line the error occurrs in the recvfrom line.
One possible explanation for this could be not providing adequate space for the remote address, though so long as your remote_size is a correct reflection of your remote, I'd expect this to cause recvfrom to return an error3, not crash. Another possibility is passing bad memory/handles (for example, if you've set up the new operator to not throw on failure, or if your socket initialization failed and you didn't bail out). It's impossible to say exactly without seeing the code initializing all the variables in play, and ideally the actual error you get in that scenario.
1 Even though sprintf can't catch this, static analysis tools (like those included in Visual Studio 2012/2013) are very capable of catching this particular bug. If you run the posted code through the default Visual Studio 2012 Code Analyzer, it will complain with:
error C4996: 'sprintf': This function or variable may be unsafe
2 Some people prefer static_cast<char*>(static_cast<void*>(&counter)) to reinterpret_cast<char*>(&counter). Both work, it's essentially a coding convention choice.
3 For example, if you were initializing remote as a SOCKADDR_IN instead of a SOCKADDR_STORAGE, you might encounter such an error if you happened to receive from an IPv6 address. This answer goes through some of the relevant gory details.