bw*****@yahoo.com wrote:
True, but then buf grows even larger. Let me explain what I am doing.
I am writing a file to a socket. I am working on designing the
protocol,
so I want to write the size of the file as well as other information
before
appending a portion of the file to the buffer. I need to make sure that
the size of the file is all ways at the same place in the buffer, and I
want to make sure the portion of the file all ways starts in the
same place.
Once that is done, the receiving end will know how to process the
packet
being received.
You are still making this incredibly too hard for what is normally done. By
hard I mean you shouldn't be converting integers to strings, etc. just to
transmit it over a socket. You're working with sockets, so we're already out
of comp.lang.c land, and I'm adding comp.unix.programmer here. As a result of
working with sockets, you SHOULD have the standard repertoire of functions
available. If you want to transmit the size of a file, previous to the file,
aka LV, or extended more, TLV (type-length-value), you do just that. However,
you design things ahead of time such that both sides know what protocol
they're speaking, and you always transmit any single object larger than a
byte in network byte order. This applies to shorts, ints, longs, etc. It does
not apply to streams of byte data. Before you even get into this territory,
it's pretty much required that you pick up a copy of W. Richard Stevens: Unix
Network Programming, Volume 1. Without it, you're going to make a lot of
novice mistakes.
In your particular example, you want to send size first, most likely as a
network byte order uint_32t and then the stream of bytes representing the
file. Extremely basic protocol, essentially:
/*
* all code below not entirely comp.lang.c safe
*/
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/uio.h>
ssize_t file_send(int, char *, size_t);
ssize_t file_recv(int, char *, size_t);
ssize_t file_send(int s, char *buf, size_t sz)
{
struct iovec packet[2];
ssize_t bw;
uint32_t nbo_sz;
/* host to network long, look it up and use it, or else */
nbo_sz = htonl(sz);
packet[0].iov_len = sizeof(nbo_sz);
packet[0].iov_base = &nbo_sz;
packet[1].iov_len = sz;
packet[1].iov_base = buf;
/*
* naive, don't do as one call and call it a day, and don't do it as
* blocking. this is entirely for simple contrived example.
* read: W. Richard Stevens: UNPv1
*/
if ((bw = writev(s, packet, 2)) == -1) {
perror("writev");
return -1;
}
return bw;
}
ssize_t file_recv(int s, char *buf, size_t sz)
{
struct iovec packet[2];
ssize_t br, brt = 0;
uint32_t nbo_sz;
/*
* in this recv example, one doesn't necessarily need to use iovecs,
* but it's a good idea as you may end up sending more than just size
* initially.
*/
packet[0].iov_len = sizeof(nbo_sz);
packet[0].iov_base = &nbo_sz;
/*
* naive, don't do as one call and call it a day, and don't do it as
* blocking. this is entirely for simple contrived example.
* read: W. Richard Stevens: UNPv1
*/
if ((br = readv(s, packet, 1)) == -1) {
perror("readv");
return -1;
}
brt += br;
/* network to host long, look it up and use it, or else */
nbo_sz = ntohl(nbo_sz);
/*
* better handle nbo_sz sz, and handle it appropriately either
* through a callback to handle the remaining bytes, realloc, etc
* or some other form of unexpected case handling or do it
* after the intial sz-max read.
*/
packet[0].iov_len = nbo_sz sz ? sz : nbo_sz; /* example only */
packet[0].iov_base = buf;
/*
* naive, don't do as one call and call it a day, and don't do it as
* blocking. this is entirely for simple contrived example.
* read: W. Richard Stevens: UNPv1
*/
if ((br = readv(s, packet, 1)) == -1) {
perror("readv");
return -1;
}
brt += br;
/*
* possibly handle nbo_sz sz here by calling a user supplied callback
* to realloc or store elsewhere or some other form of unexpected case
* handling. either way, plan for it - as it will happen.
*/
return brt;
}