我正在编写一个基本的服务器/客户端对话框,客户端发送命令后跟几个参数。
例如:
(<command> <arg1> <arg2>\n<final arg>)
//client input:
CREATE somefile.txt 19\n
some file text here
服务器解析命令,并执行操作。这是我的问题;&#39; \ n&#39;字符意味着其余的参数将在下一个发送()&#39;中提供。因此,在示例中,文件的文本在前几个参数之后出现。
&#39;错误&#39;这里是如果快速发送文件文本,这两个命令似乎放在同一个缓冲区中。
在以下示例中会出现这种情况:
//INSIDE CLIENT.C:
//INPUT 1: causes trouble
write( sock, command, strlen( command ) );
write( sock, filecontents, strlen( filecontents ) );
//INPUT 2: works fine
write( sock, command, strlen( command ) );
sleep(1);
write( sock, filecontents, strlen( filecontents ) );
//INSIDE SERVER.C:
int len = recv(client_socket, args, buffer_size, 0);//get the initial args <CREATE> <FILENAME> <BYTES>
printf("command:%s", args);
//code to parse the command and call relevant method
...
//in the "Create file" method, we wait for the contents of the file
int len = recv( client->client_socket, contents, buffer_size, 0);
printf("contents:%s", contents);
输出取决于客户端write()s:
之间的时间量//OUTPUT 1: without sleep():
//The first recv gets all the data,
//then the next recv gets the whole message again (from the next client iteration,
command:CREATE file.txt 19
some file text here
contents:CREATE file.txt 19
some file text here
//OUTPUT 2: with sleep():
command:CREATE file.txt 19
contents:some file text here
目标: 我每次都需要它看起来像输出2。问题是,我无法控制客户端的操作,因此sleep()不是永久的解决方案。我应该怎么解决这个问题?
注意:我非常确定通过更改recv的处理方式可以解决问题,因此我不会想到需要更多代码。如果我发帖更多,请告诉我。
编辑:我唯一知道的是,初始命令即CREATE file.txt 89\n
将始终以&#39; \ n&#39;无论。如果recv()一次收到所有数据,那么我就可以读到第一个&#39; \ n&#39;。但是当情况不是这样时,消息(和缓冲区)被分成两部分,如下例所示:
CASE 1:
int len = recv( client->client_socket, args, buffer_size, 0);
//args == "CREATE file.txt 19\nsome file text here"
CASE 2:
int len = recv( client->client_socket, args, buffer_size, 0);
//args == "CREATE file.txt 19\n"
CASE 3://<--might have made this one up, could not reproduce
int len = recv( client->client_socket, args, buffer_size, 0);
//args == "CREATE file.txt 19\n" <--- this means I have to recv again
int len2 = recv( client->client_socket, args, buffer_size, 0);
//possibilities:
//
//the second recv() might contain:
//args == "CREATE file.txt 19\nsome file text here"
//or
//args == "some file text here"
在案例1中,在第一个recv中检索所有数据,所有数据都在一个缓冲区中。 在情况2中,前半部分存储在缓冲区中。现在,在这种情况下,我知道我需要等待其余的数据到达。但是,到它到达时,我怎么知道缓冲区中的数据是否仍包含&#34;创建&#34;部?
//I would need something like this:
if(commands still in buffer from recv, and the text file data has arrived)
{
//then skip over those args, and begin reading form a different index
}
else {
//read the data from the start.
}
但是我无法想出办法来做到这一点......这有意义吗?
答案 0 :(得分:2)
你不应该那么信任网络。
正如您所发现的,recv()
只会收到个人send()
的数据。您的字节从send()
函数到recv()
的路径中涉及很多缓冲,所以没有人会保证这一点。
我建议你 - do advise at University :) - 实现某种使用固定长度字段来了解可变长度数据的协议。
例如,您可以通过在4个字节之前发送指示要发送的实际数据的字节数,然后是您想要的数据来启动要发送的每条消息。在接收器上,首先是recv()
,固定大小为4个字节,然后分配一个字节块,该字节块的数量与该数字所代表的一样多,最后你recv()
那个字节很多。
通过这种方式,您始终知道要接收多少数据,何时分割数据等等 - 至少as much as the network lets you。
此外,请勿忘记检查send()
和recv()
返回值,因为它们可能表示您仍然缺少某些字节 - 并在需要时重试。