PDA

View Full Version : Sending image data over UDP


damalo
02-25-2005, 03:37 PM
Howdy folks,

Im putting together a protocol to send images over UDP at the moment. Not too easy but im having a fundamental problem.

Im reading an image file into a buffer and trying to send that over UDP. The buffer data is quite small as the image is only 1px in size.

Then using another function im outputting the buffer to a new image. Which works fine. The problem is sending that over UDP to another client.

When i go to send this buffered image info it sends only the first 4 bits. After which i think there is some stop line which the sendto seems to be interpreting as end of the buffer - so the receiving client only picks up a fraction of the intended payload. Any ideas how to get around this?

ill paste my code here...

(this code example doesnt include the function to output the buffer data to a new image - but trust me that part is working)


#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/time.h>

#define REMOTE_SERVER_PORT 1501
#define MAX_MSG 100


int main(int argc, char *argv[]) {

int sd, rc, i;
struct sockaddr_in cliAddr, remoteServAddr;
struct hostent *h;
FILE* filein;
long lSize;
char *buffer;

/* check command line args */
if(argc<3) {
printf("usage : %s <server> <data1> ... <dataN> \n", argv[0]);
exit(1);
}

/* get server IP address (no check if input is IP address or DNS name */
h = gethostbyname(argv[1]);
if(h==NULL) {
printf("%s: unknown host '%s' \n", argv[0], argv[1]);
exit(1);
}

printf("%s: sending data to '%s' (IP : %s) \n", argv[0], h->h_name,
inet_ntoa(*(struct in_addr *)h->h_addr_list[0]));

remoteServAddr.sin_family = h->h_addrtype;
memcpy((char *) &remoteServAddr.sin_addr.s_addr,
h->h_addr_list[0], h->h_length);
remoteServAddr.sin_port = htons(REMOTE_SERVER_PORT);

/* socket creation */
sd = socket(AF_INET,SOCK_DGRAM,0);
if(sd<0) {
printf("%s: cannot open socket \n",argv[0]);
exit(1);
}

/* bind any port */
cliAddr.sin_family = AF_INET;
cliAddr.sin_addr.s_addr = htonl(INADDR_ANY);
cliAddr.sin_port = htons(0);

rc = bind(sd, (struct sockaddr *) &cliAddr, sizeof(cliAddr));
if(rc<0) {
printf("%s: cannot bind port\n", argv[0]);
exit(1);
}



//open file
filein = fopen("image.jpg","rb+");
//get its size
fseek(filein, 0, SEEK_END);
lSize = ftell(filein);
rewind (filein);

//malloc the buffer big enough for image data

buffer = (char*) malloc (lSize);
//read image data into buffer
fread (buffer,1,lSize,filein);


//...create duplicate image (works ok)


// send data - Have also tried sizeof(buffer)

for(i=2;i<argc;i++) {
rc = sendto(sd, buffer, sizeof(buffer)+1, 0,
(struct sockaddr *) &remoteServAddr,
sizeof(remoteServAddr));

if(rc<0) {
printf("%s: cannot send data %d \n",argv[0],i-1);
close(sd);
exit(1);
}

}

return 1;

}




Cheers!

i3839
02-25-2005, 05:33 PM
You can't count on sizeof(buffer) to return the size of the allocated memory. Perhaps some older gcc versions do what you expect, but at least gcc 3.4 returns 4.

damalo
02-25-2005, 05:39 PM
forgetting about the sizeof(buffer)

this issue is that the buffer contains image data - this image data contains some pretty nasty characters which sendto() in UDP cannot handel. Hence in the example im working on at the moment i only get to send the first 4 bytes cause there is one of these nasty characters. The buffer contains many thousand of bytes so i have to come up with a way of dealing with these nasty characters on a case by case basis so that the sendto() will interpret them and send them off

i3839
02-25-2005, 06:08 PM
Would be rather a coincidence if the nasty data is always the same, causing you to always just send 4 bytes. I would be surprised if sendto looks at the data at all: it just sends it blindly, no matter what it is. All nasty bytes are handled in lower layers like ethernet, but that's not sendto's problem, and if they didn't handle nasty bytes they would have found out very long ago, won't you think? But you seem pretty sure about it though, so can't really argue...

All I can say is that you do
sendto(sd, buffer, sizeof(buffer)+1, 0,
(struct sockaddr *) &remoteServAddr,
sizeof(remoteServAddr));
I wonder if you do the same in the receiving code, but that's another matter.

Also the "for(i=2;i<argc;i++)" seems a bit useless, or at least incositent with the help output, I'd expect the code to send different files instead of the same one argc times.

damalo
02-25-2005, 06:18 PM
ok - points noted.

But how could i get around it quitting out once it gets to one of these nasty characters? There could be 1000/10000 in each buffer. I wont know exactly where they are.

i cant copy my image data buffer into a normal char array and send that because it too will assume one of these nasty characters is an EOF mark.

I suppose in total the question is - How can i send binary data in UDP and in what format (struct/char)?

i3839
02-25-2005, 06:24 PM
Send/recv/sento/recvfrom are binary interfaces, they just send or receive data. If that data is from a char array doesn't mean that that char array is a valid string (NUL terminated). Only your program may assume that it is text, in which case there's a communication problem between the writer of the read code and the writer of the send code.

RobSeace
02-25-2005, 09:22 PM
The value you SHOULD be passing as the length to sendto() is "lSize", the same
value you pass to malloc(), which represents the actual size of the buffer... As has
been said already, sizeof() on a pointer will give you the native pointer size (typically
4, on a 32-bit system)... And, as has already been said, but which I'll repeat just
for confirmation, sendto() doesn't care one bit about the data you're sending... It
is most definitely NOT related to anything in the data stream...

damalo
02-25-2005, 10:19 PM
Yip - You were right there Rob. I wasnt in think mode at all. Im afraid thats what 10 hours of straight programming does sometimes. IT seems to be taking the messy info a bit better now.

Thanks for giving me a virtual slap in the shape of some info!

D

Loco
03-01-2005, 09:16 PM
Yip - You were right there Rob. I wasnt in think mode at all. Im afraid thats what 10 hours of straight programming does sometimes. IT seems to be taking the messy info a bit better now.

Thanks for giving me a virtual slap in the shape of some info!

D

Damalo,

Not only Rob was right. He pointed out something that i3839 had already written (many times BTW). I think you should also thank i3839.

I give i3839 a happy face for his precise answer: :)

damalo
03-01-2005, 10:38 PM
Thanks for pointing that out loco

- Thanks to both of you :)

For the record my problem was... (well amoung others :P )

//malloc the buffer big enough for image data

buffer = (char*) malloc (lSize); <----should have taken out the *
//read image data into buffer
fread (buffer,1,lSize,filein);



I now have a nice multicast streaming protocol which can serve 1 or 10 or 20 clients using the same bandwith. Pretty nice thing multicast :)

Thanks again one and all

i3839
03-02-2005, 12:19 AM
I was just prodding damalo without effect, while Rob took the clue bat and gave a good swing. ;-)

The sad thing about multicast is that it's hardly supported and killed by NAT, if not other things. So what's left is more or less LAN, but there the main advantages: less bandwidth usage and scalability, aren't that useful. I so hope that with IPv6 everyone follows standards and supports proper multicasting.