Unix Socket发送/接收长消息

时间:2015-04-21 12:05:10

标签: c sockets unix tcp unix-socket

我正在使用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;

}

3 个答案:

答案 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)在每次发送的消息的开头和结尾使用一些分隔符来标记开头和结尾,以便在接收方进行检查。