0

I'm writing some server/client program in C Windows. I don't know if I'm sending and receiving buffers the right way, on google I only see people error checking it but not checking if the send() function sent less bytes then expected. This is an example from my project:

Client:

// send buffer size
uint32_t num = htonl(sizeBuffer);
char* converted_num = (char*)#
res = send(ClientSocket, converted_num, sizeof(uint32_t), 0); 
if (res == SOCKET_ERROR)
{
    printf("error send\n");
}

// send buffer
while (totalSent < sizeBuffer)
{
    sent = send(ClientSocket, totalBuffer, sizeBuffer, 0);
    totalSent += sent;
    printf("sent: %d\n", sent);
    printf("totalSent: %d\n", totalSent);
}

Server:

// recv buffer size
char b[sizeof(uint32_t)];
r = recv(s, b, sizeof(uint32_t), 0);
if (r == SOCKET_ERROR)
{
    printf("error recv\n");
}
uint32_t sizeBuffer = ntohl_ch(&b[0]);

// recv buffer
while (totalReceived < sizeBuffer)
{
    received = recv(s, buffer, sizeBuffer, 0);
    strcat(totalBuffer, buffer);
    bzero(buffer, 18384);
    totalReceived += received;
    printf("received: %d\n", received);
    printf("totalReceived: %d\n", totalReceived);
}
printf("%s", totalBuffer);

The reason I use strcat() is because when I use printf() inside the while() loop it gets printed weirdly, like the previous buffer gets printed and the new buffer gets printed on top. I don't know why it behaves like this.

Is this the right way to send and receive buffers? And do I also have to check whether the size (num) of the buffer is send correctly, like how I send the buffer itself? If yes, how can I do that?

Y K
  • 71
  • 1
  • 6
  • 3
    `strcat` works only if source and destination are properly terminated strings. This is not the case when you receive incomplete data. You should add up the number of bytes received, move the buffer position and reduce the number of bytes to receive accordingly. Similar for `send`: You have to move the buffer position to after the data that you already sent and decrease the number of bytes to send accordingly. An example for `read` is shown here: https://stackoverflow.com/a/666788/10622916 – Bodo Jun 17 '22 at 12:16
  • What do you mean by moving the buffer position? – Y K Jun 17 '22 at 12:26
  • See the line `result = read(socket, buffer + bytesRead, x - bytesRead);` in the linked answer. – Bodo Jun 17 '22 at 12:30
  • Do you mean that I have to cut off the bytes from my buffer that are already sent? So that's the first x bytes of buffer – Y K Jun 17 '22 at 12:31
  • I'm starting to get it. But what happens at buffer + bytesRead? – Y K Jun 17 '22 at 12:37
  • Does it move the position to the x'th index in that buffer? – Y K Jun 17 '22 at 12:38
  • In the first iteration it tries to read `x - 0` characters to position `buffer + 0`. Assuming it reads 10 bytes, it will set `bytesRead = 10`, and in the next iteration it will try to read `x - 10` bytes to `buffer + 10`. Assuming it reads 20 bytes, it will add 20 to `bytesRead` and try to read `x - 30` byted to `buffer + 30` etc. (In reality it might read in bigger chunks.) – Bodo Jun 17 '22 at 12:51
  • I understand it now, thank you. Last question: Do I have to do the same when sending and receiving binary buffers, like files? – Y K Jun 17 '22 at 13:10
  • I'm not sure I understand the point of the question. For text data you might need to read until you found a line termination or whatever marks the end of the data you want to process, for binary data you might have to read a fixed total size. For writing you have to repeat as necessary until you have sent the expected total size. I don't know the details on Windows. On UNIX or Linux I would recommend this handling of short read or write in any case. – Bodo Jun 17 '22 at 13:27
  • Send sends "some data" and recv receives "some data", not more than you asked for, but often less. So yes, you have to repeat both. The reason you get a "new buffer on top of old buffer" is because of how strings work and the fact recv does not make a string – user253751 Jun 17 '22 at 13:46
  • @user253751 i solved the string issue using bzero() – Y K Jun 17 '22 at 14:01
  • Your workaround using `strcat` and `bzero` will not work for binary data. I strongly suggest to use the solution from the answer I referenced in my first comment. – Bodo Jun 17 '22 at 14:36
  • Do you understand why bzero solved it? – user253751 Jun 17 '22 at 14:36
  • You're right, it won't work with binary data. But it does work with strings, what bzero does is this: it overwrites everything in the buffer with 0's. Before this it just wrote the new buffer on top of the old one. – Y K Jun 17 '22 at 16:26
  • When I send my buffer size, do I also have to do the same? – Y K Jun 17 '22 at 16:27
  • Your buffer size recv is broken anyway. What happens if the recv loads only one byte of the size? – Martin James Jun 17 '22 at 19:35
  • The bzero call is a cargo-cult waste of cycles. It's in the wrong place anyway. – Martin James Jun 17 '22 at 19:37
  • @MartinJames What do you mean by broken? – Y K Jun 17 '22 at 20:35
  • 'r' could be loaded with any number 1...sizeof(uint32_t), all are valid possibilities. You must understand TCP byte streaming, or you will fail to generate reliable code. – Martin James Jun 17 '22 at 20:46
  • @Bodo Hi, I made 2 function, one for sending string buffer, one for receiving it. Do you mind if I post the functions here so you can review them? – Y K Jun 19 '22 at 14:45
  • @YK You should at least write a new question. If you don't have a problem with the code and only need a code review, https://codereview.stackexchange.com/ might be the right site. – Bodo Jun 20 '22 at 08:06

0 Answers0