epoll и reassembled TCP segments
От: lnkuser  
Дата: 18.04.15 17:31
Оценка:
Подскажите пожалуйста хоть в какую сторону рыть, сутки проб и поисков не дали результата...

Пишу простенький веб-сервер сугубо для своих нужно, нужно отправлять и получать JSON.

Тестил в Firefox, все отлично, запустил на Webkit-подобном движке и...
Обнаружил что tcp пакет с хедером и контент с json идут в разных tcp пакетах! (суммарный размер прмиерно 300 байт и оно почему -то разбивает на 2 пакета!)
В Firefox, опять таки, такого нет. Один пакет.



Мой код с epoll просыпается когда есть данные на сокете, но считывается только хедер без данных...

Код работы с epoll в целом стандартный:

    constexpr uint16_t EPOLL_SIZE {1024};

    static struct epoll_event events[EPOLL_SIZE];
    int sockfd {0};
    int epoll_events_count {0};

    struct sockaddr_in client_addr;
    socklen_t socklen = sizeof(struct sockaddr_in);

    epfd_ = epoll_create(EPOLL_SIZE);
    ev_.data.fd = sockfd_;
    ev_.events = EPOLLIN | EPOLLPRI | EPOLLERR | EPOLLHUP;
    epoll_ctl(epfd_, EPOLL_CTL_ADD, sockfd_, &ev_);

    while (true) {
        try {
            process_loop();

            unsigned int timeout = process_get_standby();

            epoll_events_count = epoll_wait(epfd_, events, EPOLL_SIZE, timeout);
            for (int n=0; n<epoll_events_count; n++) {

                int fd = events[n].data.fd;
                if (fd == sockfd_) {
                    sockfd = accept(sockfd_, (struct sockaddr *)&client_addr, &socklen);
                    if (sockfd < 0)
                        continue;

                    //tcout() << "[info] established connection from: " << inet_ntoa(client_addr.sin_addr) << ":" << ntohs(client_addr.sin_port) << ", socket: " << sockfd << std::endl;

                    uint32_t ip = ntohl(client_addr.sin_addr.s_addr);
                    uint16_t port = ntohs(client_addr.sin_port);

                    process_client_connect(sockfd, ip, port);
                }
                else {
                    if ((events[n].events & EPOLLERR) || (events[n].events & EPOLLHUP)) {
                        process_client_disconnect(fd);
                        continue;
                    }
                    else if (events[n].events & EPOLLIN || EPOLLPRI) {
                        process_data_received(fd);
                    }
                }
            }
        }
        catch (std::exception &e) {
            *lgr << LogLevel::error << "[exception] in server class: " << e.what();
        }
        catch (...) {
            *lgr << LogLevel::error << "[exception] in server class";
        }
    }


Код считывания с сокета, на котором есть данные:
нижеприведенный код создает буффер определенного размера, если считаны данный длинной с буффер — расширяем его еще и так пока считается меньше чем шаг буффера, потом ресайзим буффер

    int32_t rv {0};
    static constexpr uint32_t incoming_buffer_size {2048};
    try {
        buffer.clear();
        do {
            uint32_t current_position = buffer.size();
            buffer.resize(buffer.size() + incoming_buffer_size);
            rv = read(sockfd, buffer.data() + current_position, incoming_buffer_size);
            *lgr << LogLevel::info << __func__ << " rv " << rv;
            if (rv < 0) {
                *lgr << LogLevel::error << __func__ <<  "() broken connection detected during read";
                throw std::exception();
            }
            if ((rv < static_cast<int32_t>(incoming_buffer_size)) and (buffer.size() == incoming_buffer_size))
                buffer.resize(rv);
            else if (rv < static_cast<int32_t>(incoming_buffer_size))
                buffer.resize(current_position + rv);
        }
        while (rv == static_cast<int32_t>(incoming_buffer_size));
    }
    catch (...) {
        *lgr << LogLevel::error << __func__ << " exception";
        return -1;
    }

    *lgr << LogLevel::info << __func__ << " buffer.size() " << buffer.size();
    return buffer.size();



опция TCP_DEFER_ACCEPT не помогает, может она не для этого предназначена? вроде как должна

Тоесть мой код видит первый пакет и все, второй не видит. Wireshark говорит что пакет доставлен.


Запустил пример на асинхронном boost, тоже самое...

Подскажите пожалуйста
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.