简体   繁体   English

Unix套接字发送/接收长消息

[英]Unix Socket sending/receiving long messages

I am writing a simple application layer protocol using tcp and I encounter a problem. 我正在使用tcp编写一个简单的应用程序层协议,但遇到问题。 I want to make fragmentation in message sending because messages are so long. 我想在消息发送中进行分段,因为消息太长了。 But I cannot synchronize the process and the client reads empty buffer before the server writes the data. 但是我无法同步该过程,并且客户端在服务器写入数据之前先读取空缓冲区。 The messages are approximately 4mb. 消息大约为4mb。 How can I write these methods? 如何编写这些方法?

For client 对于客户

void send_message(string message);

string receive_message()

For server 对于服务器

void send_message(int sock,string message)

string receive_message(int sock)

My functions are below 我的功能如下

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;

}

You have to implement the framing in your own code. 您必须在自己的代码中实现框架。 TCP is a "stream" meaning it just sends bytes without any sort of start/end indication. TCP是“流”,意味着它仅发送字节而没有任何类型的开始/结束指示。 (UDP is packet-based but not suitable for packets of your size.) (UDP基于数据包,但不适合您大小的数据包。)

The simplest method would be to write a 4-byte length to the socket and have the receiving side read those bytes, remembering that endianess is an issue (use htonl() and ntohl() to convert local representations to "network order"). 最简单的方法是将4个字节的长度写入套接字,并让接收方读取这些字节,并记住字节顺序是个问题(使用htonl()ntohl()将本地表示形式转换为“网络顺序”)。

Then proceed to read that number of bytes. 然后继续读取该字节数。 When that is done, you've received your message. 完成后,您已经收到您的消息。

If you use blocking reads, it'll be fairly simple -- if you get less then the connection has broken. 如果您使用阻止读取,那将非常简单-如果获得的次数较少,则说明连接已断开。 If you use non-blocking reads, you have to assemble the pieces you get (you could even get the length in pieces, though unlikely) back with each read call. 如果使用非阻塞读取,则必须在每次读取调用时将得到的片段组装在一起(尽管可能甚至可以分段读取长度)。

There are other ways of framing your data but this is the simplest. 还有其他框架数据的方法,但这是最简单的。

You're ignoring the count returned by recv() . 您将忽略recv()返回的计数。 Instead of constructing a string with the entire buffer, construct it from only that many bytes of the buffer. 与其从整个缓冲区构造字符串,不如从缓冲区的那么多字节构造字符串。

1)Create send_message() and receive_message() using send() and recv() . 1)使用send()recv()创建send_message()receive_message() recv()

2)Select appropriate flags in recv() Read recv() man page for flags . 2)在recv() )中选择适当的标志读取recv()手册页中的标志。 http://linux.die.net/man/2/recv . http://linux.die.net/man/2/recv

3)Use some delimiter at the start and end of the message transmitted at each time to mark the beginning and end so that check can be made at receiver side. 3)在每次发送的消息的开头和结尾处使用一些定界符来标记开头和结尾,以便可以在接收方进行检查。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM