从Cocket到End字符读取C中的数据

时间:2014-05-01 03:29:01

标签: c sockets

编辑:在评论中已经证明,定义长度应该产生相同的结果,并且不会使用任何重要的额外数据。如果您正在寻找一种在运行程序的计算机之间发送数据的方法,那么发送长度比读取终止字符要好。 BonzaiThePenguin有一些非常好的观点,你应该看看。

但出于教育目的:我从来没有找到能够为标准C套接字执行此操作的良好示例代码,这些套接字处理的数据并非全部在一个数据包中接收,或者一个数据包中包含多个单独的消息。简单地重复调用recv并不适用于所有情况。

这是我自己在下面回答的问题之一,但我对自己的回答并不是100%自信。

2 个答案:

答案 0 :(得分:1)

允许客户端指定正在发送的邮件的大小并不危险#39;。这个词中的大多数协议都是这样做的,包括HTTP和SSL。只有在实施不受限制的情况下才能正确检查消息,这才是危险的。

你的建议的致命缺陷是它不适用于二进制数据:你必须引入一个转义字符,以便终止字符可以出现在一个消息中,然后你当然也需要逃避逃逸。所有这些都增加了两端的处理和数据复制。

答案 1 :(得分:0)

这是我想出的。我不能保证这是完美的,因为我不是专业人士,所以如果有任何错误,我(以及其他寻求帮助的人)会非常感激,如果有人会指出它们。

上下文:socket是套接字,buffer是存储所有网络输入的数组,line是存储从缓冲区中提取的一条消息的数组(这是程序其余部分使用的),length是两者的长度输入数组,并且recvLength是指向存储在函数外部的整数的指针,该整数最初应为0,不应由其他任何内容释放或修改。也就是说,它应该在同一个套接字上多次调用此函数。此函数返回行数组中输出的数据的长度。

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;

}

简单示例用法:

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;
}

请注意,这并不总是将行保留为以null结尾的字符串。如果您愿意,可以轻松修改。