【问题标题】:Unix Socket sending/receiving long messagesUnix Socket 发送/接收长消息
【发布时间】:2015-06-28 14:05:07
【问题描述】:

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

}

【问题讨论】:

  • 你试过什么?是什么给你带来了麻烦?你看过select电话吗?
  • 没有。我该如何使用?我添加了上面的代码。
  • 想了想,select只有当你有多个不同客户端的连接时才需要。简单的发送/接收模式不需要它

标签: c sockets unix tcp unix-socket


【解决方案1】:

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

最简单的方法是将 4 字节长度写入套接字并让接收端读取这些字节,记住 endianess 是一个问题(使用 htonl()ntohl() 将本地表示转换为“网络秩序”)。

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

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

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

【讨论】:

    【解决方案2】:

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

    【讨论】:

    • 我明白了。我是一名 java 开发人员,c 对我来说有点难:)
    • 它与 C 无关。Java 中也会出现同样的问题。
    【解决方案3】:

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

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

    3)在每次传输的消息的开头和结尾处使用一些分隔符来标记开头和结尾,以便在接收端进行检查。

    【讨论】:

    • TCP 不是基于消息的。没有办法等待。
    • 设置适当的标志,例如什么?
    • 原来的回答是“like MSG_WAITALL”。
    猜你喜欢
    • 2016-01-30
    • 1970-01-01
    • 2019-11-08
    • 2018-03-31
    • 2014-10-30
    • 1970-01-01
    • 1970-01-01
    • 2011-08-07
    • 2015-10-02
    相关资源
    最近更新 更多