简体   繁体   English

从套接字读取C语言的数据直到结束字符

[英]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. BonzaiThePenguin有一些非常好的方面您应该注意。

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. 但是出于教育目的:我从来没有找到好的示例代码来为标准C套接字执行此操作,该标准C套接字处理的情况是,一个包中未全部接收数据,或者一个包中包含多个单独的消息。 Simply calling recv repeatedly will not work in all cases. 简单地反复调用recv并非在所有情况下都可行。

This is one of those questions where I've answered it myself below, but I'm not 100% confident in my response. 这是我自己在下面回答的问题之一,但是我对自己的回答没有100%的信心。

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. 这个词中的大多数协议都可以做到这一点,包括HTTP和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. 上下文:socket是套接字,buffer是存储所有网络输入的数组,line是仅存储从缓冲区提取的一条消息的数组(这是程序的其余部分使用的),length是两个输入数组的长度,和recvLength是指向存储在函数外部的整数的指针,该整数最初应为0,并且不应由其他任何东西释放或修改。 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. 如果您愿意,可以轻松进行修改。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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