Unix Socket отправка / получение длинных сообщений

Я пишу простой протокол прикладного уровня, используя tcp, и я столкнулся с проблемой. Я хочу сделать фрагментацию при отправке сообщений, потому что сообщения очень длинные. Но я не могу синхронизировать процесс, и клиент читает пустой буфер, прежде чем сервер записывает данные. Сообщения примерно 4 МБ. Как я могу написать эти методы?

Для клиента

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 ответа

Решение

Вы должны реализовать кадрирование в своем собственном коде. TCP - это "поток", то есть он просто отправляет байты без указания начала / конца. (UDP основан на пакетах, но не подходит для пакетов вашего размера.)

Простейшим способом было бы записать 4-байтовую длину в сокет и получить принимающую сторону для чтения этих байтов, помня, что проблема с порядком байтов является проблемой (используйте htonl() а также ntohl() преобразовать локальные представления в "сетевой порядок").

Затем перейдите к чтению этого количества байтов. Когда это будет сделано, вы получите свое сообщение.

Если вы используете блокировку чтения, это будет довольно просто - если вы получите меньше, то соединение разорвано. Если вы используете неблокирующее чтение, вы должны собирать части, которые вы получаете (вы могли бы даже получить длину в частях, хотя вряд ли), обратно с каждым вызовом чтения.

Есть и другие способы создания ваших данных, но это самый простой способ.

Вы игнорируете счет, возвращенный recv(), Вместо того чтобы создавать строку со всем буфером, создавайте ее только из такого количества байтов буфера.

1) Создать send_message() а также receive_message() с помощью send() а также recv(),

2) Выберите соответствующие флаги в recv() Читать recv() справочная страница для флагов. http://linux.die.net/man/2/recv.

3) Используйте некоторый разделитель в начале и конце сообщения, передаваемого каждый раз, чтобы отметить начало и конец, чтобы можно было проверить на стороне получателя.

Другие вопросы по тегам