Unix Socket sending/receiving 长消息

Unix Socket sending/receiving long messages

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

}

1)使用send()recv()创建send_message()receive_message()

2)Select recv() 中的适当标志阅读 recv() 标志手册页。 http://linux.die.net/man/2/recv.

3)在每次发送的报文的首尾使用一些定界符来标记首尾,以便接收端进行校验。

您必须在自己的代码中实现框架。 TCP 是一个 "stream" 意味着它只发送字节而没有任何类型的 start/end 指示。 (UDP 是基于数据包的,但不适合您这种大小的数据包。)

最简单的方法是将 4 字节长度写入套接字,让接收端读取这些字节,记住 endianess 是一个问题(使用 htonl()ntohl() 将本地表示转换为 "network order").

然后继续读取该字节数。完成后,您就收到了消息。

如果您使用阻塞读取,这将相当简单——如果您读取的较少,则连接已断开。如果你使用非阻塞读取,你必须 assemble 你得到的片段(你甚至可以得到片段的长度,虽然不太可能)在每次读取调用时返回。

还有其他构建数据的方法,但这是最简单的方法。

您忽略了 recv() 返回的计数。不要用整个缓冲区构造一个字符串,而是只从缓冲区的那么多字节构造它。