Reputation: 3701
I am trying to write some xml data to a socket in C. I can print the xml string to the screen using:
printf("<tag1>%d</tag1>"
"<tag2>%s</tag2>"
"<tag3>%s</tag3>"
"<tag4>%d</tag4>",
int1,
str2,
str3,
int4);
Instead of printing to stdout, I try to snprintf
that string to a buffer (char[]
), then write the buffer's contents to a socket. Unfortunately, I imagine that here the buffer could be full during the write of either str2
or str3
and perhaps not even big enough to contain either string.
Using snprintf
it is easy to check whether I was able to write all the data to the buffer, but not easy to continue where I left off after sending buffer contents to a socket.
Basically: Is there functionality that would let me send, say, 64 bytes at a time of "%d%s%s%d"
to a socket, should the formatted string be longer than 64 bytes?
If this functionality does not exist I'm interested in what workarounds you'd suggest (If it helps, you can assume the %s
fields are populated by an evil robot that tries to overflow your buffer, regardless of size).
Upvotes: 3
Views: 3091
Reputation: 1
On Linux at least with GNU libc you could use asprintf(3) (which gives a malloc
-ed string) or dprintf(3) (which prints into a file descriptor).
You could also (and more portably) fdopen(3) the socket file descriptor then fprintf(3) and fflush(3) it. You could configure buffering with setvbuf(3).
fileno(3) is quite useful too...
BTW, snprintf(3) is returning the number of needed bytes. So you might code
char tinybuf[100];
char* buf = tinybuf;
int nbytes= snprintf(tinybuf, sizeof(tinybuf),
"<tag at='%d'>%s</tag>", num, string);
if (nbytes >= sizeof(tinybuf)) { // rarely happens
char *buf = malloc(nbytes+1);
if (!buf) { perror("malloc"); abort(); };
snprintf(buf, nbytes+1,
"<tag at='%d'>%s</tag>", num, string);
};
int off=0;
while (nbytes>0) {
int nbw=write(sock, buf+off, nbytes);
if (nbw>0) { off += nbw; nbytes -= nbw; };
else if (nbw<0 && errno != EINTR) { perror("write"); abort(); };
};
if (buf != tinybuf) free(buf);
This would avoid malloc
and free
in the common case that tinybuf
fits...
Upvotes: 4
Reputation: 29804
What about using fprintf
with a socket descriptor?
Something like:
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
FILE *fd = fdopen(sockfd, "w")
fprintf(fd, "<tag1>%d</tag1>"
"<tag2>%s</tag2>"
"<tag3>%s</tag3>"
"<tag4>%d</tag4>",
int1,
str2,
str3,
int4);
fflush(fd);
Upvotes: 3