简体   繁体   中英

Reading Data in C From Socket Until End Character

EDIT: It has been proven in the comments that defining the length instead should produce the same results and would not use any significant extra data. If you are looking for a way to send data between machines running your program(s), sending the length is better than reading until a terminating character. BonzaiThePenguin has some very good points you should look at.

But for educational purposes: I never found good example code that does this for standard C sockets that handles situations where the data is not all received in one packet, or multiple separate messages are contained within one packet. Simply calling recv repeatedly will not work in all cases.

This is one of those questions where I've answered it myself below, but I'm not 100% confident in my response.

It isn't 'dangerous to allow the client to specify the size of the message it is sending'. Most of the protocols in the word do that, including HTTP and SSL. It's only dangerous when implementations don't bounds-check messages properly.

The fatal flaw with your suggestion is that it doesn't work for binary data: you have to introduce an escape character so that the terminating character can appear within a message, and then of course you also need to escape the escape. All this adds processing and data copying at both ends.

Here is what I came up with. I cannot guarantee that this is perfect because I am not a professional, so if there are any mistakes, I (and anyone else looking for help) would greatly appreciate it if someone would point them out.

Context: socket is the socket, buffer is the array that stores all network input, line is the array that stores just one message extracted from buffer (which is what the rest of your program uses), length is the length of both inputted arrays, and recvLength is a pointer to an integer stored outside of the function that is meant to be 0 initially and should not be freed or modified by anything else. That is, it should persist across multiple calls to this function on the same socket. This function returns the length of the data outputted in the line array.

size_t recv_line(int socket, char* buffer, char* line, size_t length, size_t* recvLength){ //receives until '\4' (EOT character) or '\0' (null character)

size_t readHead = 0;
size_t lineIndex = 0;
char currentChar = 0;
while (1){
    for (; readHead < *recvLength; readHead = readHead + 1){
        currentChar = buffer[readHead];
        if (currentChar=='\4' || currentChar=='\0'){ //replace with the end character(s) of your choice
            if (DEBUG) printf("Received message===\n%s\n===of length %ld\n", line, lineIndex+1);
            memcpy(buffer, buffer + readHead + 1, length-(readHead)); //shift the buffer down
            *recvLength -= (readHead + 1); //without the +1, I had an "off by 1" error before!
            return lineIndex+1; //success
        }
        if (readHead >= length){
            if (DEBUG) printf("Client tried to overflow the input buffer. Disconnecting client.\n");
            *recvLength = 0;
            return 0;
        }
        line[lineIndex] = currentChar;
        lineIndex++;
    }
    *recvLength = recv(socket, buffer + readHead, length, 0);
}
printf("Unknown error in recv_line!\n");
return 0;

}

Simple example usage:

int function_listening_to_network_input(int socket){
char netBuffer[2048];
char lineBuffer[2048];
size_t recvLength = 0;

while (1==1){
size_t length = recv_line(socket, netBuffer, lineBuffer, 2048, &recvLength);
// handle it…
}
return 0;
}

Note that this does not always leave line as a null-terminated string. If you want it to, it's easy to modify.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM