我正在使用tcp编写一个简单的应用程序层协议,我遇到了一个问题。我想在消息发送中进行碎片化,因为消息太长了。但我无法同步进程,客户端在服务器写入数据之前读取空缓冲区。消息大约是4mb。我该如何编写这些方法?
对于客户
void send_message(string message);
string receive_message()
对于服务器
void send_message(int sock,string message)
string receive_message(int sock)
我的功能在
之下void send_fragment(char* buffer,int length){
int n = write(sockfd, buffer, length);
if (n < 0)
{
perror("ERROR writing to socket");
exit(1);
}
}
string receive_fragment(){
char buffer[FRAGMENT_LENGTH];
bzero(buffer,FRAGMENT_LENGTH);
int n = read(sockfd, buffer, FRAGMENT_LENGTH-1);
if (n < 0)
{
perror("ERROR reading from socket");
exit(1);
}
return string(buffer);
}
void send_message(string message){
char buffer[FRAGMENT_LENGTH];
bzero(buffer,FRAGMENT_LENGTH);
int message_length = message.length();
//computes the number of fragment
int number_of_fragment = ceil((double)message_length / FRAGMENT_LENGTH);
sprintf(buffer,"%d",number_of_fragment);
//sends the number of fragment
send_fragment(buffer,strlen(buffer));
for(int i=0;i<number_of_fragment;++i){
bzero(buffer,FRAGMENT_LENGTH);
//fragment interval
int start = i*FRAGMENT_LENGTH;
int end = (i+1)*FRAGMENT_LENGTH;
if(i==number_of_fragment-1){
end = min(end,message_length);
}
//creates a fragment
const char* fragment = message.substr(start,end).c_str();
sprintf(buffer,"%s",fragment);
//sends the fragment
send_fragment(buffer,strlen(buffer));
}
}
string receive_message(){
//receive and computes the number of fragment
string number_of_fragment_string = receive_fragment();
int number_of_fragment = atoi(number_of_fragment_string.c_str());
string message ="";
for(int i=0;i<number_of_fragment;++i){
//concatenating fragments
message += receive_fragment();
}
return message;
}
答案 0 :(得分:2)
您必须在自己的代码中实现框架。 TCP是一个“流”,意味着它只发送没有任何开始/结束指示的字节。 (UDP是基于数据包的,但不适合您的大小的数据包。)
最简单的方法是将4字节长度写入套接字并让接收方读取这些字节,记住endianess是一个问题(使用htonl()
和ntohl()
将本地表示转换为“网络订单”)。
然后继续读取该字节数。完成后,您已收到消息。
如果你使用阻塞读取,它会相当简单 - 如果你得到更少,那么连接就会中断。如果你使用非阻塞读取,你必须组装你得到的碎片(你甚至可以得到碎片的长度,尽管不太可能)回到每次读取调用。
还有其他方法可以构建您的数据,但这是最简单的方法。
答案 1 :(得分:0)
您忽略了recv()
返回的计数。不是用整个缓冲区构造一个字符串,而是仅从缓冲区的那么多字节构造它。
答案 2 :(得分:-2)
1)使用send_message()
和receive_message()
创建send()
和recv()
。
2)在recv()
阅读recv()
手册页中选择适当的标志以获取标志。 http://linux.die.net/man/2/recv
3)在每次发送的消息的开头和结尾使用一些分隔符来标记开头和结尾,以便在接收方进行检查。