Home > Archive > Unix Programming > October 2004 > while loop for recv and send to get all data doesn't work
You are viewing an archived Text-only version of the thread.
To view this thread in it's original format and/or if you want to reply to
this thread please [click here]
| Author |
while loop for recv and send to get all data doesn't work
|
|
| Alef T Veld 2004-10-11, 8:56 am |
| Hi,
I'm trying to put recv and send in a while(1) loop to ensure i get all
data from the client and from the server. Within the loop i check for <=0
, if it occurs, i do a break.
However, it does not work. It seems to keep sending data and never breaks!
I use the following loop for send:
while(1) {
if(send(sockfd,buffer,strlen(buffer),0)<=0)
break;
}
and for recv
while(1) {
if (recv(sockfd,buffer,sizeof(buffer),0)<=)
break;
}
because recv gets the entire buffer, i terminate
the buffer like this buffer[strlen(buffer)-1]='\0';
Apart from the above problem, i also realize what would happen
if the buffer did not get sent completetly,iwould get double
data because the buffer would get sent twice.
What am i doing wrong,
Alef
| |
| Lev Walkin 2004-10-11, 8:56 am |
| Alef T Veld wrote:
> Hi,
>
> I'm trying to put recv and send in a while(1) loop to ensure i get all
> data from the client and from the server. Within the loop i check for <=0
> , if it occurs, i do a break.
>
> However, it does not work. It seems to keep sending data and never breaks!
>
> I use the following loop for send:
>
> while(1) {
> if(send(sockfd,buffer,strlen(buffer),0)<=0)
> break;
> }
>
> and for recv
>
> while(1) {
> if (recv(sockfd,buffer,sizeof(buffer),0)<=)
> break;
> }
> because recv gets the entire buffer, i terminate
> the buffer like this buffer[strlen(buffer)-1]='\0';
>
> Apart from the above problem, i also realize what would happen
> if the buffer did not get sent completetly,iwould get double
> data because the buffer would get sent twice.
>
> What am i doing wrong,
Implementation.
Use this one:
int already_read = 0;
while(1) {
int rd = recv(sockfd, buffer + already_read, sizeof(buffer) -
already_read, 0);
switch(rd) {
case 0: return already_read;
case -1:
switch(errno) {
case EINTR:
case EAGAIN:
continue; /* Safe one */
}
return -1; /* Hard error */
}
already_read += rd;
}
--
Lev Walkin
vlm@lionet.info
| |
| Måns Rullgård 2004-10-11, 8:56 am |
| Alef T Veld <alef@xs2.xs4all.nl> writes:
> Hi,
>
> I'm trying to put recv and send in a while(1) loop to ensure i get all
> data from the client and from the server. Within the loop i check for <=0
> , if it occurs, i do a break.
>
> However, it does not work. It seems to keep sending data and never breaks!
>
> I use the following loop for send:
>
> while(1) {
> if(send(sockfd,buffer,strlen(buffer),0)<=0)
> break;
> }
>
> and for recv
>
> while(1) {
> if (recv(sockfd,buffer,sizeof(buffer),0)<=)
> break;
> }
> because recv gets the entire buffer, i terminate
> the buffer like this buffer[strlen(buffer)-1]='\0';
>
> Apart from the above problem, i also realize what would happen
> if the buffer did not get sent completetly,iwould get double
> data because the buffer would get sent twice.
>
> What am i doing wrong,
Here's how to do it (unless I've made some silly mistake):
#include <sys/types.h>
#include <sys/socket.h>
#include <errno.h>
size_t sendall(int fd, const void *buf, size_t len, int flags)
{
while(len > 0){
ssize_t r = send(s, buf, len, flags);
if(r >= 0){
buf += r;
len -= r;
} else if(errno != EINTR){
break;
}
}
return len;
}
This will send all the data in the buffer, if possible. It returns
the number of bytes not sent. The caller can examine errno to find
out what went wrong if this is not zero.
--
Måns Rullgård
mru@mru.ath.cx
| |
| Nils O. Selåsdal 2004-10-11, 4:00 pm |
| Alef T Veld wrote:
> because recv gets the entire buffer, i terminate
> the buffer like this buffer[strlen(buffer)-1]='\0';
The other has told you what to do for send,
note that the above is total nonsense though, strlen
would expect a nul terminated string in the first place.
You need do do similar things on the recieve side as
on the send side, possible send the nul terminator as well and
check for that if you just send C strings, or send the
length first, and read until you got lenght bytes.
| |
| Måns Rullgård 2004-10-11, 4:00 pm |
| Måns Rullgård <mru@mru.ath.cx> writes:
> Here's how to do it (unless I've made some silly mistake):
For receiving, just replace send() with recv().
--
Måns Rullgård
mru@mru.ath.cx
| |
| Fletcher Glenn 2004-10-11, 4:00 pm |
|
Alef T Veld wrote:
> Hi,
>
> I'm trying to put recv and send in a while(1) loop to ensure i get all
> data from the client and from the server. Within the loop i check for <=0
> , if it occurs, i do a break.
>
> However, it does not work. It seems to keep sending data and never breaks!
>
> I use the following loop for send:
>
> while(1) {
> if(send(sockfd,buffer,strlen(buffer),0)<=0)
> break;
> }
>
> and for recv
>
> while(1) {
> if (recv(sockfd,buffer,sizeof(buffer),0)<=)
> break;
> }
> because recv gets the entire buffer, i terminate
> the buffer like this buffer[strlen(buffer)-1]='\0';
>
> Apart from the above problem, i also realize what would happen
> if the buffer did not get sent completetly,iwould get double
> data because the buffer would get sent twice.
>
> What am i doing wrong,
> Alef
You are aware that your send loop has no condition for termination. The
only time that it would quit sending is if you got an error, or the
system send buffer was temporarily full. If you were trying to overcome
partial sends, then you have to do your own pointer and count control.
--
Fletcher Glenn
| |
|
|
>
> You are aware that your send loop has no condition for termination. The
> only time that it would quit sending is if you got an error, or the
> system send buffer was temporarily full. If you were trying to overcome
> partial sends, then you have to do your own pointer and count control.
I thought that it would break upon receiving 0, indicating the server has
closed connection or that there was no more data to send.
>
> --
>
> Fletcher Glenn
--
new
| |
|
|
>
>
> Use this one:
I will, thanks, but why doesn't mine work? Should'nt it break on receiving
0 or -1?
>
> int already_read = 0;
| |
| Bjorn Reese 2004-10-12, 3:58 pm |
| On Mon, 11 Oct 2004 14:38:49 +0200, Måns Rullgård wrote:
> ssize_t r = send(s, buf, len, flags);
> if(r >= 0){
Minor point, but send() returns -1 on error, not some arbitrary
negative number, so it may be more correct to use "r != -1".
You can also make the code more readable by defining a macro
or constant from -1 (e.g. SYS_ERROR)
Btw, this comment applies to most Unix system calls.
--
mail1dotstofanetdotdk
| |
| Martin Carpenter 2004-10-12, 3:58 pm |
|
"Bjorn Reese" <breese@see.signature> wrote:
>
> Minor point, but send() returns -1 on error, not some arbitrary
> negative number, so it may be more correct to use "r != -1".
Mmm, but that's not very defensive, is it? Imagine a broken socket lib whose
recv() sometimes returns -3. I wouldn't want to ignore this.
| |
| Måns Rullgård 2004-10-12, 3:58 pm |
| "Martin Carpenter" <mcarpenter@free.fr> writes:
> "Bjorn Reese" <breese@see.signature> wrote:
>
>
> Mmm, but that's not very defensive, is it? Imagine a broken socket lib whose
> recv() sometimes returns -3. I wouldn't want to ignore this.
And < 0 is quicker to type than == -1.
--
Måns Rullgård
mru@mru.ath.cx
| |
| Lev Walkin 2004-10-12, 8:56 pm |
| Bjorn Reese wrote:
> On Mon, 11 Oct 2004 14:38:49 +0200, M=E5ns Rullg=E5rd wrote:
>=20
>=20
>=20
>=20
> Minor point, but send() returns -1 on error, not some arbitrary
> negative number, so it may be more correct to use "r !=3D -1".
> You can also make the code more readable by defining a macro
> or constant from -1 (e.g. SYS_ERROR)
>=20
> Btw, this comment applies to most Unix system calls.
This minor point easily turns into a major one. Suppose, one
did the suggested change:
size_t sendall(int fd, const void *buf, size_t len, int flags)
{
while(len > 0){
ssize_t r =3D send(s, buf, len, flags);
if(r !=3D -1){
buf +=3D r;
len -=3D r;
} else if(errno !=3D EINTR){
break;
}
}
return len;
}
Here we see clearly, that IF, by WHATEVER reason, send() returns
negative result different from -1 (say, ssize_t type is redefined
in process and becomes signed short type, or WHATEVER), than the buf will=
be
incremented by a negative number of bytes. Not very defensive, huh?
--=20
Lev Walkin
vlm@lionet.info
| |
| Bjorn Reese 2004-10-13, 9:09 am |
| On Tue, 12 Oct 2004 16:42:46 -0700, Lev Walkin wrote:
> Here we see clearly, that IF, by WHATEVER reason, send() returns
> negative result different from -1 (say, ssize_t type is redefined
> in process and becomes signed short type, or WHATEVER), than the buf will be
> incremented by a negative number of bytes. Not very defensive, huh?
That is because your code example erroneously processes the return
value as an ssize_t.
Look at the signature of the send() function. The input length is
a size_t, whereas the ouput length is a ssize_t. So, the input
length may be unsigned and the output length signed. The reason
for this is to allow the special return code of -1.
Now, what happens if you send more than SSIZE_MAX bytes? This is
legal, but your code will fail as you have described above.
The proper way to handle the situation is to (1) check of the
return value is -1, and if not (2) cast it into size_t before use.
--
mail1dotstofanetdotdk
| |
| Bjorn Reese 2004-10-13, 9:09 am |
| On Tue, 12 Oct 2004 19:11:10 +0200, Måns Rullgård wrote:
> "Martin Carpenter" <mcarpenter@free.fr> writes:
-3 is a legal return value indicating that SIZE_MAX-3 bytes have
been sent.
Which broken socket library are you thinking of. I know of many
errors in different libraries on different platforms -- this is
not one of them.
[color=darkred]
> And < 0 is quicker to type than == -1.
Write a keyboard macro if you are concerned with the typing speed.
--
mail1dotstofanetdotdk
| |
| Måns Rullgård 2004-10-13, 3:59 pm |
| "Bjorn Reese" <breese@see.signature> writes:
> On Tue, 12 Oct 2004 19:11:10 +0200, Måns Rullgård wrote:
>
>
>
> -3 is a legal return value indicating that SIZE_MAX-3 bytes have
> been sent.
Who in their right mind would want to send 2^64 - 3 bytes of data?
--
Måns Rullgård
mru@mru.ath.cx
| |
| Martin Carpenter 2004-10-13, 3:59 pm |
|
"Bjorn Reese" <breese@see.signature> wrote:
> -3 is a legal return value indicating that SIZE_MAX-3 bytes have
> been sent.
Ugh. I hadn't noticed that len is size_t - i.e., potentially much "bigger"
than the (absolute value of the) return value. Do any/most/all
implementations do this?
"-1 is a legal return value indicating that SIZE_MAX-1 bytes have been
sent". Hopefully the library takes care of this corner case...
> Which broken socket library are you thinking of. I know of many
> errors in different libraries on different platforms -- this is
> not one of them.
Sorry, I meant -5 :-p
| |
| Bjorn Reese 2004-10-14, 3:59 pm |
| On Wed, 13 Oct 2004 15:37:32 +0200, Måns Rullgård wrote:
> Who in their right mind would want to send 2^64 - 3 bytes of data?
Which standard requires size_t to be at least 64-bit wide?
SIZE_MAX can be as small as 65535 (see section 7.18.3 in C99, or the
description of <stdint.h> in SUSv3). Even worse, the example code in
question will start malfunctioning at SIZE_MAX / 2 + 1.
--
mail1dotstofanetdotdk
| |
| James Antill 2004-10-14, 8:56 pm |
| On Wed, 13 Oct 2004 13:50:25 +0200, Bjorn Reese wrote:
> On Tue, 12 Oct 2004 16:42:46 -0700, Lev Walkin wrote:
>
>
> That is because your code example erroneously processes the return
> value as an ssize_t.
>
> Look at the signature of the send() function. The input length is
> a size_t, whereas the ouput length is a ssize_t. So, the input
> length may be unsigned and the output length signed. The reason
> for this is to allow the special return code of -1.
>
> Now, what happens if you send more than SSIZE_MAX bytes? This is
> legal, but your code will fail as you have described above.
To be fair, all platforms I know of refuse to do this. And SuS3
allows it but doesn't mandate it.
> The proper way to handle the situation is to (1) check of the
> return value is -1, and if not (2) cast it into size_t before use.
While I personally do this, and advocate it (apart from anything else it
seems clearer). I know there have been bugs in Linux where
mismatches between the kernel and libc meant syscalls could return
negative errno numbers (Ie. -FOO instead of -1, errno = FOO). So I can
somewhat understand the rationalization of using < 0. But I'd still
recommend fixing the OS at that point.
--
James Antill -- james@and.org
Need an efficient and powerful string library for C?
http://www.and.org/vstr/
| |
| Måns Rullgård 2004-10-15, 8:56 am |
| "Bjorn Reese" <breese@see.signature> writes:
> On Wed, 13 Oct 2004 15:37:32 +0200, Måns Rullgård wrote:
>
>
> Which standard requires size_t to be at least 64-bit wide?
>
> SIZE_MAX can be as small as 65535 (see section 7.18.3 in C99, or the
> description of <stdint.h> in SUSv3). Even worse, the example code in
> question will start malfunctioning at SIZE_MAX / 2 + 1.
OK, here's an updated version (untested):
#include <sys/types.h>
#include <sys/socket.h>
#include <errno.h>
size_t sendall(int fd, const void *buf, size_t len, int flags)
{
while(len > 0){
ssize_t r = send(s, buf, len, flags);
size_t s = r;
if(r == -1){
if(errno){
if(errno != EINTR)
break;
else
s = 0;
}
}
buf += s;
len -= s;
}
return len;
}
--
Måns Rullgård
mru@mru.ath.cx
|
|
|
|
|