首先,我以前从未使用过 C(主要是 Java,这就是您会发现我编写一些天真的 C 代码的原因)。我正在用 C 编写一个简单的命令解释器。我有这样的东西:
//Initialization code
if (select(fdmax+1, &read_fds, NULL, NULL, NULL) == -1) {
perror("Select dead");
exit(EXIT_FAILURE);
}
....
....
//Loop through connections to see who has the data ready
//If the data is ready
if ((nbytes = recv(i, buf, sizeof(buf), 0)) > 0) {
//Do something with the message in the buffer
}
现在,如果我正在查看类似一长段命令的内容,很明显 256 字节的缓冲区将无法获取整个命令。目前,我正在使用 2056 字节缓冲区来获取整个命令。但是如果我想使用 256 字节缓冲区,我该怎么做呢?我是否跟踪哪个客户给了我什么数据并将其附加到某个缓冲区?我的意思是,使用二维数组之类的东西?
最佳答案
是的,通常的方法是为每个客户端设置一个“我已收到但未处理的数据”的缓冲区,其大小足以容纳最大的协议(protocol)消息。
您读入该缓冲区(始终跟踪缓冲区中当前有多少数据),每次读取后,检查是否有完整的消息(或消息),因为您可能会在一次!)。如果这样做,您将处理该消息,将其从缓冲区中移除并将所有剩余数据移动到缓冲区的开头。
大致是这样的:
for (i = 0; i < nclients; i++)
{
if (!FD_ISSET(client[i].fd, &read_fds))
continue;
nbytes = recv(client[i].fd, client[i].buf + client[i].bytes, sizeof(client[i].buf) - client[i].bytes, 0);
if (nbytes > 0)
{
client[i].bytes += nbytes;
while (check_for_message(client[i]))
{
size_t message_len;
message_len = process_message(client[i]);
client[i].bytes -= message_len;
memmove(client[i].buf, client[i].buf + message_len, client[i].bytes);
}
}
else
/* Handle client close or error */
}
顺便说一下,如果 select()
返回 -1,您应该检查 errno == EINTR
,然后再次循环 - 这不是 fatal error 。
关于C:使用选择调用,当我阅读时,我如何跟踪数据?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2159628/