Home > Mobile >  Proper way to break out of a recv() loop in C
Proper way to break out of a recv() loop in C

Time:03-29

I wrote a server/client program where I can copy files from client to server. The problem is that I can't break out of the while loop in my server when writing to the file is done. I can only open the new copied file when I close my server program because the file doesn't get closed with fclose(copyFile). The file gets copied successfully everytime. However it does work properly when I run the server/client on the same machine but when I move the client to another pc, the server keeps blocking on recv() in my server.

Server:

while (1)
{
    int res = recv(s, buf, BUFSIZ, 0);
    if (res == SOCKET_ERROR)
    {
        printf("3 error %d\n", WSAGetLastError);
        break;
    }
    fwrite(buf, 1, res, copyFile);
    if (strncmp(buf, "exit", 4) == 0)
    {
        break;
    }
}
fclose(copyFile);

Client:

while (size == BUFSIZ)
{
    size = fread(buf, 1, BUFSIZ, originalFile);
    int r = send(ClientSocket, buf, size, 0);
    if (r == SOCKET_ERROR)
    {
        printf("1 error: %d\n", WSAGetLastError);
    }
}
int r = send(ClientSocket, "exit", 4, 0);
if (r == SOCKET_ERROR)
{
    printf("2 error: %d\n", WSAGetLastError);
}
fclose(originalFile);

How can I properly exit the while() loop in my server?

CodePudding user response:

You are attempting to indicate the end of the file with the word "exit", but there are at least two problems with that:

  • if the file being transferred contains the word "exit" then that could be misinterpreted as an end-of-file marker, and

  • you seem to be assuming that your send() calls at the client will be paired one-to-one with recv() calls at the server, so that the "exit" can be relied upon to appear at the beginning of the buffer when the server receives it. That is not a safe assumption.

(Note also that even if the server did happen to receive the "exit" at the beginning of the buffer, you would still write it to the file before recognizing it as an end-of-file marker. If this were the only issue then it would be easy to fix.)

You need a workable application-level protocol to help client and server communicate -- something that layers the needed additional structure on top of the flat byte stream that the socket connection provides. The "exit" terminator is an attempt at that, but it is not a workable solution, at least not by itself.

In contrast, consider HTTP: messages consist of a sequence of headers that are individually and as a group recognizable by their lexical form, followed by the message body. Among the things that the headers can convey is the length of the message body, and this is how the recipient can recognize the end of the message body without the sender closing the connection.

You do not need to implement HTTP, but you can be inspired by it. If you want to transmit messages with arbitrary length and content, without signaling the end of the message by closing the connection, then your best bet is to tell the recipient in advance how many bytes to expect in the message. That could be as simple as prepending a fixed-length message-length field.

  • Related