Sign in to follow this  

Send data with winsock

This topic is 4744 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Howdy yall, I'm able to send messages back and forth via int send( SOCKET s, const char* buf, int len, int flags ); I'm able to make a little chat program with this, however...We are trying to send floats from server to client and vise versa. How is this possible when the send command expects a character buffer?

Share this post


Link to post
Share on other sites
a char* is just a block of memory. really, they should have called it 'byte' instead of 'char'. you can copy any POD type into a char array using memcpy. ex:


//a 4 byte buffer
char buffer[4];
float some_float = 34.3f;

memcpy(buffer,&some_float,sizeof(some_float));

send(..,(const char*)buffer,4,..);


you can stuff as much data as you want into a char array. be it 100 floats or just 1..

Share this post


Link to post
Share on other sites
So, your char array is 4 because you need one for each character of the float...34.3f?

And if that is the case then what if you have a float 23.3434523 and then use memcpy to put it into a char array that only hold 4 chars...will it truncate for you?

And last question...once the server sends the char*, how do you save it on the client. Would you put what you recieve in a char buffer or can you just save it directly to a float?

Share this post


Link to post
Share on other sites
well, to be honest i'm not an exactly an expert in this area, but..

a character is really just one byte of memory. a float is 4 bytes. just think of a character array as a block of memory. this means you can copy a float, or any other type for that matter, into this block of memory.

no matter what your float's value is, it will only take up 4 bytes. the amount of memory it uses does NOT have to do with how many numbers are in the float. 34.3 and 23.3434523 both take up 4 bytes of memory.

when you receive this char buffer on the other end, yes, you can copy it directly into a float or whatever type it should be. for example, if your receiving the char buffer with a float from my first example, it would look like this:


float my_float;
memcpy(&myfloat,packet_data,sizeof(my_float));

Share this post


Link to post
Share on other sites
the more precision you use, the more bytes needed. float use 4 bytes, double use 8 byte if not mistaken, mayb 6? check it :P
so it is your design issue to decide either use 4 byte char or 8 byte char to store floating point value.
hope this help.

regards,
chung

Share this post


Link to post
Share on other sites
//Sender
float val = 35.454588f;
char buffer[4];
memcpy(buffer, (char*)&val, 4, 0);
send(sock, buffer, 4, 0);


//Receiver
char buffer[4];
float val;
recv(sock, buffer, 4, 0);
memcpy((char*)&val, buffer, 4);
val = val + 1.0f; //val = 35.454588 + 1.0 = 36.454588


Note: if you increase Sender's val precision to 35.4545889f, and still using 4 byte float,the system will truncate and store 35.454588 only. unless you use double, and increase buffer to 8 bytes instead of 4.


regards,
Chung


Share this post


Link to post
Share on other sites
instead of memcpy i usually like to do the following:

char arr[4];
float x = 3.14159f;

*(float*)arr = x;

to unpacket it

float y = *(float*)arr
Use the power of the compiler to do your dirty work.

This trick is usually about 5 times faster :)

Share this post


Link to post
Share on other sites
If all you want to do is send one float then just use:

send(sock, (char *) &f, sizeof(f), 0);

There's no need to memcpy anything. And for gods sake please done hardcode the length to be 4. That's why we have sizeof.

People get hung up on socket stuff using char* everywhere. It's just a holdover from the bad old days when C had basically no type checking. If it could be redone today they would be void* or perhaps u_char* instead.

Actually to be technical you might have to buffer up the float first - if you're doing endian conversion or float-point format conversion. The former depends on your wire protocol and if you only care about Windows then there's no reason to not using native (little-endian) on the wire. The latter is pretty much irrelevant these days.

Share this post


Link to post
Share on other sites
So you only use memcopy when you want to send more than one thing at once?

I'm not really grasping this concept. If you only send one float you don't use memcopy but if you have more than one, why not just repeat the code without memcopy to do it multiple times?

And also, does memcopy append the data to the end of the char array?, because if that were true, then how exactly would you access all the data in the array once its recieved if it is a different amount of bytes? will each memcopy put the data into a new index in the buffer array?

Share this post


Link to post
Share on other sites
Quote:
Original post by Steers
So you only use memcopy when you want to send more than one thing at once?


i cannot think of any real situation in which you only want to send a single piece of data. at the very least, you need an indentifier to know what that data means. how else would you know how to parse a packet?

Quote:

I'm not really grasping this concept. If you only send one float you don't use memcopy but if you have more than one, why not just repeat the code without memcopy to do it multiple times?


you would want to group your data into a single packet, with a way to indentify what this packet means. otherwise, your just sending blind data out. how will the receiver know how to parse it? what does that data mean?

Quote:

And also, does memcopy append the data to the end of the char array?, because if that were true, then how exactly would you access all the data in the array once its recieved if it is a different amount of bytes? will each memcopy put the data into a new index in the buffer array?

memcpy will write the data to the point in the array you pass it. in the given examples, we write it at the very begining of the array. however, you can write it in the middle or at the end of the array as well. you should really google for tutorials on arrays and pointers to brush up on this.

anyway, maybe an example will help you understand. lets say we are on the client and want to build a packet which we will send to the server our X and Y position. so, this packet needs a way to say "hey, this is our position", and then our position. so, it would look something like this:

//this message is 9 bytes long. 8 bytes for our position and 1 byte MSGID
char buff[9];

const unsigned char MSGID_MY_POSITION = 0;
float x = 40.3f;
float y = 35.2f;

//write the ID into the packet
memcpy(buff,&MSGID_MY_POSITION,1);

//write the X position
memcpy(buff+1,&x,sizeof(x));

//write the y position
memcpy(buff+5,&y,sizeof(y));

send(..,buff,9,..);

on the receiving end, you read the first byte to find out what kind of message this is. now that you know that its a MY_POSITION message, you know that the next 8 bytes are my x/y position.

Share this post


Link to post
Share on other sites
Quote:
I'm not really grasping this concept. If you only send one float you don't use memcopy but if you have more than one, why not just repeat the code without memcopy to do it multiple times?


If you're using TCP you could do that. TCP at the application level is just a stream of data, there are no such things at packets. Issuing 10 little sends is no different than issuing 1 big one (approximately - that's not really true but you should get the basics down before worrying about the details).

If you're using UDP you probably can't do that. UDP does have a concept of packets at the application level and each time you call send you're in a different packet. Issuing 10 little sends is very different than one big one.

Lets try a different tack....

All send does is send a bunch of bytes. That's all the char* is - a pointer to bunch of bytes. If you do the memcpy then what you're doing is copying a bunch of bytes from one place to another and then sending the new copy instead of the old one.

You need to forget that "char*" means a string or a pointer to characters. In this case it doesn't. It just means a pointer to bunch of random bytes. They could be the bytes that make up a float or the bytes that make up a struct or yes even the bytes that make up a string - send doesn't care. All it cares about is getting those bytes shoved down to the net.

Share this post


Link to post
Share on other sites
this is starting to come together, thanks yall...
Grave,
-----------------------------
char buff[9];//9 bytes of data for storing

const unsigned char MSGID_MY_POSITION = 0;//An ID that says the bytes of this packet are x and y
float x = 40.3f;//what we want to send
float y = 35.2f;//and this too

//write the ID
memcpy(buff,&MSGID_MY_POSITION,1);//(data storage array, &data to copy,size in bytes)

//write the X position
memcpy(buff+1,&x,sizeof(x)); //buff+1 because we need to start at index 1

//write the y position
memcpy(buff+5,&y,sizeof(y));//buff+5 because we used 1-4 for our first float
------------------------------
are my comments correct?
If so this was very helpful, thank you

Share this post


Link to post
Share on other sites
yes, your comments do look right.

well, this one jumped out at me a bit. "const unsigned char MSGID_MY_POSITION = 0;//An ID that says the bytes of this packet are x and y".

really, this ID is just used for your own purposes, and the name and value of it do not really matter. you just use it so you know what kind of message the packet is (so you know how much and what type of data to extract out of the packet past this single byte). for example, when you received this message, you would do something like this:


unsigned char msg_id;

memcpy(&msg_id,packet_data,1);

switch(msg_id)
{
case MSGID_MY_POSITION:
{

//its a position packet, so we should now extract 2 floats
float x,y;
memcpy(&x,packet_data+1,sizeof(x));
memcpy(&y,packet_data+5,sizeof(y));
break;
}
case MSGID_SOME_OTHER_MESSAGE:
{
//we got some other message..
break;
}
case MSGID_ANOTHER_DIFFERENT_MESSAGE:
{
//another message
break;
}
case MSGID_ETC
{
//..
break;
}
}

Share this post


Link to post
Share on other sites
Ok, we have a problem, here's some code, any help would be greatly appreciated.
The client in this code, sends a char to the server, the char is the ID that asks for it to send a float back. The code runs fine, but instead of, displaying our float we sent (which is 1.0), it displays 0. We also display our buffer array, but it says the value is !!. The out put of the program is at the end of this code...

//here the client code (not all of it mind you, just the send and recieve stuff)

int nBytes;//number of bytes we expect to recieve...
#define MAX_SIZE 13//max size of our packet
float val1 = 0.0f;//the valuue of the float we recieve
float val2 = 0.0f//float2
float val3 = 0.0f//float3
char buffer[13];//our buffer
char id=19;//the ID that the server wil evaluate
memcpy(buffer, (char*)&id,1);//copy our message id into the buffer
size = htonl(size);//makes sure size is still kool with the server
//send the size the server should expect....and make sure there were no errors sending
if ((nBytes = send(mySocket, (char*)&size, sizeof(size), 0)) == SOCKET_ERROR) {
printf("Send Failed!\n");//say we do have an error
}
size = ntohl(size);//make sure our size is still kool //send the actual id
if ((nBytes = send(mySocket,buffer, size, 0)) == SOCKET_ERROR) {
printf("Send Failed!\n");
}
//recieve the size
nBytes = recv(mySocket, (char*)&size, sizeof(size), 0); //recieve the float
nBytes = recv(mySocket, buffer, size, 0);
//copy the id, first float, second and third
memcpy(&id, buffer,1);
memcpy(&val, buffer+1, 4);
memcpy(&val, buffer+5, 4);
memcpy(&val, buffer+9, 4);
//do we have an error
if (nBytes == SOCKET_ERROR) {
printf("Recv Failed!\n");
}
else
{
printf("Reply Received The Number Is : %d\n", val);
}
Sleep(9000);





//heres the server code

int nBytes;//number of bytes we will recieve
#define MAX_SIZE 13//max size of our buffer
char buffer[MAX_SIZE];//our buffer to send
unsigned long size;//how much we will recieve
//recieve size from the client
nBytes = recv(clientSocket, (char*)&size, sizeof(size), 0);
//did we get an error? and deal with it if we did
if (nBytes == SOCKET_ERROR) {
int error = WSAGetLastError();
if (error == WSAECONNRESET) {
WaitForSingleObject(mutexHandle, INFINITE);
FD_CLR(clientSocket, &masterSet);
ReleaseMutex(mutexHandle);
closesocket(clientSocket);
printf("client on %d disconnected\n", clientSocket);
continue;
} else {
printf("Recv Failed!\n");
gQuitFlag = true;
break;
}
}

if (nBytes == 0) {//if we dont have anything
WaitForSingleObject(mutexHandle, INFINITE);
FD_CLR(clientSocket, &masterSet);
ReleaseMutex(mutexHandle);
closesocket(clientSocket);
printf("client on %d disconnected\n", clientSocket);
continue;
}
size = ntohl(size);//make sure size is kool with the client
float val1;
float val2;
float val3;
char id = 19;//random id we chose for send floats
nBytes = recv(clientSocket, buffer, size, 0);//recieve the id
//if we have an error
if (nBytes == SOCKET_ERROR) {
printf("Recv Failed!\n");
gQuitFlag = true;
break;
}

val1 = 1.0f;//we chose 1.0 randomly for this program
val2 = 1.0f;
val3 = 1.0f;
memcpy(buffer, &id, 1);//copy id to our buffer
memcpy(buffer+1,(char*)&val1,sizeof(val));//copy our first float
memcpy(buffer+5,(char*)&val2,sizeof(val));//copy our second
memcpy(buffer+9,(char*)&val3,sizeof(val));//copy our third
send(clientSocket, (char*)&size, sizeof(size), 0);//send the size of our packet
send(clientSocket, buffer, 13, 0);//send the actual packet
printf("Float sent to client %d. \n", clientSocket);//ran good

printf("Message Received from client on %d : %s\n", clientSocket, buffer);//worked out ok






the output of the program is...
on the client it says...
client started
enter any key to recieve a float:
reply recieved: the number is 0

on the server it says...
server started
client on 84 connected
Float sent to client on 84 : !! <----that is the value of buffer
client on 84 disconnected


Thanks in advance for any help, and sorry if its a stupid mistake. But thats how we newbies are.
-Steers

[Edited by - Steers on December 15, 2004 5:54:27 PM]

Share this post


Link to post
Share on other sites
please use [ source ] [ /source ] tags for your code ;)

even better: create a struct for your messages:


struct PosMessage
{
float x,y,z;
unsigned int someStuffYouMightNeed;
}

//Client........

PosMessage msg;
msg.x = 3.145f;
msg.y = 12.5f;
msg.z = 9.5f;
msg.someExtraStuffYouMightNeed = 0xDEADBEEF;
int msgType = ID_MSG_POSITION;

send(socket,(char*)&msgType,sizeof(msgType),0);
send(socket,(char*)&msg,sizeof(msg),0);

//Server.........

int msgType;
recv(socket,(char*)&msgType,sizeof(msgType),0);

switch (msgType)
{
case ID_MSG_POSITION:
{
PosMessage msg;
recv(socket,(char*)&msg,sizeof(msg),0);
//do something with msg......
}
break;
case .....:
....
....
break;
default:
printf("Error, unknown message received.\n");
break;
}


****EDIT***
Don't know, however if thats gonna be an issue with byte alignment and stuff...
something similar works for me though.

Share this post


Link to post
Share on other sites
Thanks madhed, except for that dead beef comment... lol

We created a struct but when we tried to send it, it said...

error C2664: 'recv' : cannot convert parameter 1 from 'unsigned int (__stdcall *)(int,int,int)' to 'unsigned int'

are we forgetting something? we copied and pasted your code, then changed it to our variables...

Share this post


Link to post
Share on other sites
Regarding the previous printing problem, you don't print a "float" using %s; you print a "float" using %f. I still don't think you've gotten the difference between memory, a buffer, a pointer, a float, and a char down. To do network programming, it's important that you understand the basic tools of your programming language first.

Share this post


Link to post
Share on other sites
well, the %f was what we were missing the whole time. Although we have solved our problem with everyones help here, I think this just shows that we are no where ready to takle more complex problems with winsock. If anyone has a good tutorial using send and recieve, we would greatly appreciate it.

Thanks, Steers

Share this post


Link to post
Share on other sites
hey Steers. to be honest, i don't think you are at all ready to try to learn network programming. i'm not trying to be harsh, or rude. but from your post i another forum and from this one, it is clear you are not ready. i am only posting this so that you don't get very frustrated, and give up because your stuck on a problem that has to deal with the basics of the language. if you start from the bottom, and work your way up, you have a much greater chance of succeeding.

anyway, good luck in whatever you do.

Share this post


Link to post
Share on other sites
If you were refering to including the librarys in Visual c++, i've been using a different compiler. We are not stupid programmers. And i don't doubt that winsock and network programming can be challanging. However, whether it is too difficult i believe should be decided by us. But thank you for your concern. We would really only like resources to learn from rather than demotivation.

Share this post


Link to post
Share on other sites
whoops, sorry. i was confusing you with this thread.

although, to be honest, my comment still applies a little to you. finding basic error messages like the ones you struggled with kind of jumps out at me like your biting off too much to chew. and please dont be offended by it or feel i was trying to make you un-motivated. i was actually only trying to help, believe it or not. part of being a programmer is learning how to take constructive critisism [smile].

Share this post


Link to post
Share on other sites

This topic is 4744 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this