0

I'm having an issue with Socket in C. Packet size is set to 3072 in sock option like this :

int         recvBuff = 3072;
int         recvLowAt = 2;

if (setsockopt(sock, SOL_SOCKET, SO_RCVLOWAT, &recvLowAt, sizeof(recvLowAt)) < 0) {
    LOGE("Error setsockopt rcvlowat -> %s\n", strerror(errno));
    close(sock);
    return -1;
}

if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &recvBuff, sizeof(recvBuff)) < 0) {
    LOGE("Error setsockopt rcvbuf -> %s\n", strerror(errno));
    close(sock);
    return -1;
}

Sometime packet is < 3072 and I would like to get it even if it's less than 3072

if ((size = recv(sock, buffer, BUFF_SIZE, 0)) < 0) {
    LOGE("Error recv -> %s\n", strerror(errno));
    size = 0;
} else {
    LOGI("%d bytes received\n", size);
}

Output is :

1448 bytes received
2896 bytes received
1448 bytes received

And I would like an output like this :

Output is :

3072 bytes received
3072 bytes received
3072 bytes received
500 bytes received
Whole data has been sended !

I tried to use MSG_WAITALL as a flag in recv but last packet is not sended...

Can I have some help? Thanks!

X6Entrepreneur
  • 971
  • 2
  • 10
  • 30

3 Answers3

0

socket recv call does not always return the entire data that the sender had sent in its send call. You need to keep calling recv and check may be from length or data content if you got entire data or not

Pras
  • 4,047
  • 10
  • 20
0

I would like to get it even if it's less than 3072

You will.

I would like an output like this

You won't. TCP isn't obliged to transfer more than one byte at a time in blocking mode. If you want 3072 (or whatever) bytes at once, you will have to loop.

NB The two statements quoted are mutually contradictory.

user207421
  • 305,947
  • 44
  • 307
  • 483
  • Is it possible to force with MSG_WAITALL to retrieve a packet less than the BUFF_SIZE? – X6Entrepreneur May 04 '17 at 11:42
  • Maybe at end of stream, otherwise no. – user207421 May 04 '17 at 11:43
  • As I said in my post. MSG_WAITALL waits for all data size to be sended. How to force it retrieve that last packet < 3072 (for example)..? How to know it's the end of the stream? – X6Entrepreneur May 04 '17 at 11:50
  • As it says in the *man* page, what you said in your post isn't true. It waits for the entire data size to be sent *or* end of stream *or* an interrupt *or* an error. – user207421 May 05 '17 at 00:12
  • _Waiting for a buffer to be completely sent_ **is not the same as** _waiting for a complete buffer to be filled with incoming data_. Please check this, as probably **that option is meant for blocking the writer process until all data has been received and acknowledged**, and that's a completely different scenario. – Luis Colorado May 05 '17 at 06:40
  • Well, just checked and it seems to be a receiving side option. That's a socket option (not a protocol or something at lower levels) so it's completely protocol dependant, as the note _it is useless in UDP_ confirms. The functionality requested is easily implemented in user space, and no sense to implement it in kernel space as a general function (the needing scenarios are too low to need an implementation) – Luis Colorado May 05 '17 at 06:50
0

Needing to completely fill the buffer is a rare scenario that normally doesn't require to be implemented in kernel side. To implement it in user space, you can simply add this code to yours (it's only three lines of code!!!):

unsigned char buffer[SIZE_OF_BUFFER]; /* this is the buffer */
int n, /* auxiliary variable */
    bsz = 0; /* <-- actual buffer size */

/* just loop reading until the whole buffer is full of data, or EOF or ERROR */
while (bsz < sizeof buffer && 
       (n = recv(socket, buffer + bsz, sizeof buffer - bsz, flags)) > 0)
    bsz += n; /* see NOTE */

/* here, (bsz >= sizeof buffer) || (n <= 0), ==> BUFFER FULL, EOF in socket, or some other error happened */
if (n < 0) { 
    /* process error command */
} else if (n == 0) { 
    /* process EOF in connection */
} else {
    /* process a completely filled buffer */
}

This can be implemented also as a for loop:

for(bsz = 0;
    bsz < sizeof buffer &&
    (n = recv(socket, buffer + bsz, sizeof buffer - bsz, flags)) > 0;
    bsz += n) continue;  /* used continue; as only ; for an empty loop body is weird */

NOTE

Well, the assertion (bsz >= sizeof buffer) is actually more restrictive, and can be written as (bsz == sizeof buffer) as the recv syscall always warrants that the returned value is lesser than or equal to the requested number of bytes. This results in that, after the execution of the loop body, new_bsz <= old_bsz + (sizeof buffer - old_bsz) or new_bsz <= sizeof buffer. So finally, both assertions are true (bsz >= sizeof buffer and bsz <= sizeof buffer, which implies bsz == sizeof buffer). QED.

Luis Colorado
  • 10,974
  • 1
  • 16
  • 31