Событие чтения получено перед записью в kqueue

У меня проблема с моим кодом, я пытаюсь создать HTTP-сервер, используя C++ 98 в MacOS, и я ожидаю, что блок чтения будет выполнен перед блоком записи, но происходит обратное, и я не не знаю почему. Поэтому я ожидаю сначала прочитать запрос, а затем отправить ответ. а здесь все наоборот это мой код:

/************************ CONSTRUCTORS/DESTRUCTOR ************************/
webserv::Server::Server(int addr, int port)
{
    this->sock.create_socket(AF_INET, SOCK_STREAM, 0);
    this->sock.bind_socket(addr, port);
    this->sock.listen_socket(__MAX_BACKLOG__);
}

webserv::Server::~Server() {}

/************************ MEMBER FUNCTION ************************/
void    webserv::Server::lunch()
{
    this->kq.create_event(this->sock.getSocket(), EVFILT_READ);
    while (1)
        this->_lunch_worker();
}

void    webserv::Server::_lunch_worker(void)
{
    int ev_count = this->kq.get_event();
    static const char* index_html = "HTTP/1.0 200 OK\r\n" \
                                    "Content-Length: 86\r\n\r\n" \
                                    "<!DOCTYPE html>" \
                                    "<html><head>Hello, world!</head><body><h1>cdn-ish...</h1></body></html>\r\n";
    char buf[10000];

    for (int i = 0; i < ev_count; i++) {
        int fd = this->kq.get_fd(i);

        if (fd < 0) continue;
        if (fd == this->sock.getSocket()) {
            
            int clientaddr_size = sizeof(this->sock.getAddress());

            int clientfd = this->sock.accept_socket();
            if (clientfd < 0) {
                perror("accept");
                close(fd);
                return ;
            }
            this->kq.create_event(clientfd, EVFILT_READ);
            if (fcntl(clientfd, F_SETFL, O_NONBLOCK) < 0) {
                perror("fcntl");
                close(clientfd);
                close(fd);
            }
            this->kq.create_event(clientfd, EVFILT_WRITE, EV_ADD | EV_ONESHOT);
        // EXPECTING THIS BLOCK TO BE CHECKED/EXECUTED FIRST
        // BUT INSTEAD THE NEXT BLOCK (WRITE BLOCK) IS EXECUTED FIRST
        // THEN IN THE SECOND ITERATION THE READ BLOCK IS BEING EXECUTED
        } else if (this->kq.is_read_available(i)) {
            int len;
            std::cout << "READ" << std::endl;
            // memset(buf, 0, sizeof(buf));
            if ((len = recv(fd, buf, sizeof(buf), 0)) == 0) {
                std::cout << "READ: FD CLOSED = " << fd << std::endl;
                close(fd);
            }
            else if (len > 0)
            {
            }
            std::cout << "READ: LEN = " << len << std::endl;
        } else if (this->kq.is_write_available(i)) {
            int len = 0;
            if ((len = send(fd, index_html, strlen(index_html), 0)) != 0) {
            }
            std::cout << "WRITE: LEN = " << len << std::endl;
        }
    }
}

и класс очереди:

/***********************************************************************
* FILENAME :        Kqueue.cpp
*
* DESCRIPTION :
*       This File is the implementation of the functions
*       Defined in Kqueue.hpp
*
**/

# include "./Kqueue.hpp"
# include "../../OutputColors.hpp"

/************************ CONSTRUCTORS/DESTRUCTOR ************************/
webserv::Kqueue::Kqueue()
{
    this->_kq = kqueue();
    std::cout << "KQUEUE CREATED" << std::endl;
    this->test_error(this->_kq, "Creating Kqueue :");
    this->_n_ev = 0;
}

webserv::Kqueue::~Kqueue()
{
    close(this->_kq);
}

/************************ MEMBER FUNCTIONS ************************/
void    webserv::Kqueue::set_event(int fd, int filter, int flags, void *udata)
{
    EV_SET(&this->_ev_set, fd, filter, flags, 0, 0, udata);
}

void    webserv::Kqueue::add_event(void)
{
    int ret;

    ret = kevent(this->_kq, &this->_ev_set, 1, NULL, 0, NULL);
    this->test_error(ret, "Kqueue/add_even functions");
}

int     webserv::Kqueue::get_event(void)
{
    this->_n_ev = kevent(this->_kq, NULL, 0, this->_ev_list, __EV_LIST_SIZE__, NULL);
    this->test_error(this->_n_ev, "Kqueue/get_event function:");
    return (this->_n_ev);
}

void    webserv::Kqueue::create_event(int fd, int filter, int flags, void *udata)
{
    this->set_event(fd, filter, flags, udata);
    this->add_event();
}

bool    webserv::Kqueue::isEOF(int index)
{
    if (this->_n_ev <= index)
        this->test_error(-1, "Kqueue/isEOF function:");
    return (this->_ev_list[index].flags & EV_EOF);
}

bool    webserv::Kqueue::is_read_available(int index)
{
    if (this->_n_ev <= index)
        this->test_error(-1, "Kqueue/is_read_available function:");
    return (this->_ev_list[index].filter == EVFILT_READ);
}

bool    webserv::Kqueue::is_write_available(int index)
{
    if (this->_n_ev <= index)
        this->test_error(-1, "Kqueue/is_write_available function:");
    return (this->_ev_list[index].filter == EVFILT_WRITE);
}

void    webserv::Kqueue::test_error(int fd, const std::string &str)
{
    if (fd < 0)
    {
        std::cerr << RED << str << " ";
        perror("The following error occured: ");
        std::cerr << RESET;
        exit(EXIT_FAILURE);
    }
}

/************************ GETTERS/SETTERS ************************/
struct kevent   *webserv::Kqueue::get_event_list()
{
    return (this->_ev_list);
}

int &webserv::Kqueue::get_kq()
{
    return (this->_kq);
}

int             webserv::Kqueue::get_fd(int index)
{
    if (this->_n_ev <= index)
        this->test_error(-1, "Kqueue/get_ev_list function:");
    return (this->_ev_list[index].ident);
}

void    webserv::Kqueue::set_kqueue(int fd)
{
    this->_kq = fd;
}

Кто-нибудь знает, почему в моем случае WRITE предшествует READ, я ожидаю прочитать запрос, а затем отправить ответ

Формы c голосовым вводом в React с помощью Speechly
Формы c голосовым вводом в React с помощью Speechly
Пытались ли вы когда-нибудь заполнить веб-форму в области электронной коммерции, которая требует много кликов и выбора? Вас попросят заполнить дату,...
Стилизация и валидация html-формы без использования JavaScript (только HTML/CSS)
Стилизация и валидация html-формы без использования JavaScript (только HTML/CSS)
Будучи разработчиком веб-приложений, легко впасть в заблуждение, считая, что приложение без JavaScript не имеет права на жизнь. Нам становится удобно...
Flatpickr: простой модуль календаря для вашего приложения на React
Flatpickr: простой модуль календаря для вашего приложения на React
Если вы ищете пакет для быстрой интеграции календаря с выбором даты в ваше приложения, то библиотека Flatpickr отлично справится с этой задачей....
В чем разница между Promise и Observable?
В чем разница между Promise и Observable?
Разберитесь в этом вопросе, и вы значительно повысите уровень своей компетенции.
Что такое cURL в PHP? Встроенные функции и пример GET запроса
Что такое cURL в PHP? Встроенные функции и пример GET запроса
Клиент для URL-адресов, cURL, позволяет взаимодействовать с множеством различных серверов по множеству различных протоколов с синтаксисом URL.
Четыре эффективных способа центрирования блочных элементов в CSS
Четыре эффективных способа центрирования блочных элементов в CSS
У каждого из нас бывали случаи, когда нам нужно отцентрировать блочный элемент, но мы не знаем, как это сделать. Даже если мы реализуем какой-то...
0
0
17
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Для того, чтобы можно было читать из сокета, сначала другая сторона должна определить, что соединение завершено, затем она должна составить свой запрос и передать его по проводу. Затем ваша сторона должна получить информацию и обработать ее. Только тогда можно читать из сокета.

Чтобы можно было писать в сокет, вы должны определить, что соединение завершено. Вот и все. Если соединение завершено, можно писать.

Неудивительно, что запись в сокет возможна раньше, чем чтение из него. Вопрос в том, почему ваш код проверяет возможность записи в сокет, когда вы не хотите писать в сокет? Кроме того, почему ваш код пишет в сокет только потому, что это возможно, даже если вы даже не получили запрос с другой стороны?

Если у вас есть данные для записи на другую сторону, потому что вы еще даже не получили запрос от другой стороны, зачем вы проверяете, можно ли писать в сокет? Вы не хотите писать, даже если это возможно, так зачем проверять?

Большое спасибо за вашу помощь, ваши вопросы помогли мне определить новый фактор, который может помочь, я обнаружил, что при отладке с использованием lldb все работает, как и ожидалось, я получаю запрос и отправляю ответ. но обычное выполнение кода вызывает проблему, есть идеи по этому поводу, пожалуйста?

REVERSI 17.05.2022 02:12

@REVERSI Это просто удача. Вы ожидаете двух вещей, которые могут произойти в любом порядке, и иногда они происходят в том порядке, в котором ваш код обрабатывает их правильно, а иногда они происходят в том порядке, в котором ваш код обрабатывает их неправильно.

David Schwartz 17.05.2022 02:15

Большое спасибо, что ответили мне, последний вопрос, пожалуйста, исходя из вопросов, которые вы задали, я понимаю, что могу принять соединение, открыть его только для ЧТЕНИЯ, затем, когда я прочитаю запрос, я открою его для записи тоже . и это работает, теперь я обрабатываю запрос, а затем отправляю ответ, я просто хочу спросить ваше мнение по этому поводу, пожалуйста

REVERSI 17.05.2022 02:23

Это правильно. Проверяйте только, доступен ли сокет для записи, если вы хотите писать в него.

David Schwartz 17.05.2022 02:33

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