Модераторы: xvr

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> помогите разобраться с kqueue 
:(
    Опции темы
kometa_75
Дата 14.4.2008, 11:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 62
Регистрация: 24.10.2007

Репутация: нет
Всего: нет



Пытаюсь разобраться с kqueue, пересмотрел множество примеров и хелпов, но не могу понять один момент, а именно - как правильно удалить событие. Вот код(простой эхо-сервер):
Код

  int kq, listen_socket ;
  struct kevent kq_clients[MAX_CLIENT_NUM];
  int    kq_clients_used = 0;
  struct kevent kq_events[MAX_CLIENT_NUM];
  struct timespec timeout = {0, 1000};

  listen_socket = CreateListenSocket(); // ф-ция создаёт сокет
  if((kq = kqueue()) == -1) perror("kevent()");
  EV_SET(&change, listen_socket, EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, 0);

   EV_SET(&kq_clients[0], listen_socket, EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, 0);
   ++kq_clients_used;

  while(1)
  {
    int new_ev = kevent(kq, kq_clients_list, kq_clients_used, kq_events, MAX_CLIENT_NUM, &timeout);
    if(new_ev < 0) perror("kevent()");
    else if(new_ev > 0)
    {
       for(int i = 0; i < new_ev; ++i)
       {
         if(kq_events[i].ident == listen_socket)
         {
          JoinClient(kq_events[i].ident); // ф-ция подключает новый сокет.
          ++kq_clients_used;
         }
         else
         {
            // ф-ция принимает сообщение и отправляет его обратно
            Proc(kq_events[i].ident); 
            if( errno == ECONNRESET ) // отключение клиента
            {
               close(kq_events[i].ident); // закрываем сокет
                // удаляем событие
                EV_SET(&kq_clients[i], kq_clients[i].ident, EVFILT_READ, EV_DELETE, 0, 0, 0); 
                --kq_clients_used;
             }
          }
       }
    }
    usleep(1);
  }


Пока клиенты подключены, всё работает нормально. После отключения клиентов события всё равно продолжают поступать. Такое впечатление, что они не удаляются. Помогите, кто в курсе дела.

Это сообщение отредактировал(а) kometa_75 - 14.4.2008, 16:31
PM MAIL   Вверх
MAKCim
Дата 15.4.2008, 09:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Воін дZэна
****


Профиль
Группа: Экс. модератор
Сообщений: 5644
Регистрация: 10.12.2005
Где: Менск, РБ

Репутация: 84
Всего: 207



kometa_75
Цитата

 EV_DELETE  Removes the event from the kqueue. Events which are attached to file descriptors are automatically deleted on the last close of the descriptor.

у вас сокет закрывается

кроме того
насколько я вижу, идет уменьшение kq_clients_used
Код

--kq_clients_used;

т. е при вызове kevent() уменьшается размер передаваемого массива kevent
а с учетом того, что элемент массива kq_clients_list не перемещается, а просто помечается как удаленный (EV_DELETE), возникшее событие на сокете, полученном через JoinClient(), не будет получено 


--------------------
Ах, у елі, ах, у ёлкі, ах, у елі злыя волкі ©

PM MAIL   Вверх
kometa_75
Дата 15.4.2008, 11:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 62
Регистрация: 24.10.2007

Репутация: нет
Всего: нет



Спасибо, что ответили ))

1. Да, насчёт сокета вы были правы.
2. Не совсем понятно, что делать с массивом и счётчиком kq_clients_used. Если убрать только закрытие сокета, то сообщения о закрытии будут приходить бесконечно. Пробовал ставить EV_DISABLE | EV_DELETE, всё одно не помогает.

Очевидно, что надо что-то делать с массивом kq_change_list, но что ? Вообще в сети встретил два вида примеров:
Первый.
-событие удаляют как я, только потом иногда(почему-то) сразу вызывают что-то типа такого:
Код

kevent(kq, &kq_change_list[i], 1, NULL, 0, NULL);

причём в некоторых примерах используют локальный экземпляр struct kevent.

Второй.
-не используют макрос EV_SET. Всё вручную.
-используют какие-то свои реализации массивов с хитрым распределением памяти и т.п.
Подобные "обёртки" я не смог осилить.

PS. Встретил несколько жалоб на аналогичный моему случай. Ответов, увы, не нашёл. Неужели всё так безнадёжно. На линуксе у меня с epoll проблем никаких не было.

Это сообщение отредактировал(а) kometa_75 - 15.4.2008, 11:17
PM MAIL   Вверх
kometa_75
Дата 15.4.2008, 16:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 62
Регистрация: 24.10.2007

Репутация: нет
Всего: нет



Путём долгих проб и ошибок, наконец-то заставил работать мой пример. Вот как он теперь выглядит:
Код

  int kq, listen_socket ;
  struct kevent kq_events[MAX_CLIENT_NUM];
  struct timespec timeout = {0, 1000};

  listen_socket = CreateListenSocket(); // ф-ция создаёт сокет
  if((kq = kqueue()) == -1) perror("kevent()");

  struct kevent ke;
  EV_SET(&ke, listen_socket, EVFILT_READ, EV_ADD, 0, 0, NULL);
  if(kevent(kq, &ke, 1, 0, 0, NULL) == -1) perror("kevent()");

  while(1)
  {
    int new_ev = kevent(kq, NULL, 0, &kq_events[0], MAX_CLIENT_NUM, &timeout);
    if(new_ev < 0) perror("kevent()");
    else if(new_ev > 0)
    {
       for(int i = 0; i < new_ev; ++i)
       {
         // Удаление здесь.
         if(kq_events[i].flags & EV_EOF)
         {
            struct kevent ke;
            EV_SET(&ke, kq_events[i].ident, EVFILT_READ, EV_DELETE, 0, 0, NULL);
            if(kevent(kq, &ke, 1, 0, 0, NULL) < 0) perror("kevent()");
            close(kq_events[i].ident); // Система сама сокет почему-то не закрывает.
            continue;
          }
         if(kq_events[i].ident == listen_socket)
           JoinClient(kq_events[i].ident); // ф-ция подключает новый сокет.
         else
         {
            // ф-ция принимает сообщение и отправляет его обратно
            Proc(kq_events[i].ident); 

           // Resource temporarily unavailable.
           if(errno == EAGAIN) continue;
          }
       }
    }
    usleep(1);
  }

"Вдохновлялся" кодом отсюда - http://svn.inspircd.org/index.cgi/trunk/in...d/?pathrev=6557
ЗЫ. Так и не могу объяснить, почему именно так надо делать. Тему не закрываю, вдруг кто-нибудь ответит на вопрос - как всё-таки правильно удалять(теперь уже и работать) с этим загадочным механизмом kqueue(ох и название).

Это сообщение отредактировал(а) kometa_75 - 15.4.2008, 16:11
PM MAIL   Вверх
fray
  Дата 18.4.2008, 19:49 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 139
Регистрация: 7.6.2007

Репутация: нет
Всего: 0



я так понял это был сервер с одним клиентом. У меня тоже kqueue и тоже непонятки:
здесь один сокет и как мне кажется он дожен записать в сокет один раз потом прочитать и выйти. 

Код

        size_t NEVENTS = 1;
        int fd[NEVENTS], kq;
        struct kevent kq_events[NEVENTS];

        if ( ( kq = kqueue() ) == -1 ) err(1,"%s:%i",__FILE__,__LINE__);

        struct timespec nullts = {1, 0};
        uint16_t i;
        for (i = 0; i< NEVENTS; i++) {
            fd[i] = make_connect();
            EV_SET(&kq_events[i], fd[i], EVFILT_WRITE, EV_ADD | EV_ENABLE | EV_CLEAR, 0, 0, NULL);
            if (kevent(kq, &kq_events[i], 1, NULL, 0, &nullts) == -1 ) err(1,"%s:%i",__FILE__,__LINE__);
        }
        sleep(2);

        for (;;) {
            int n = kevent(kq, NULL, 0, kq_events, NEVENTS, &nullts);
            if (n > 0) {
                for (i = 0; i < NEVENTS; i++) {
                    if (kq_events[i].filter & EVFILT_WRITE) {
                        if ( do_write(kq_events[i].ident) > 0 ) { // пишем
                            printf("write\n");
                            EV_SET(&kq_events[i], kq_events[i].ident, EVFILT_WRITE, EV_DELETE|EV_DISABLE, 0, 0, NULL);
                            EV_SET(&kq_events[i], kq_events[i].ident, EVFILT_READ, EV_ENABLE , 0, 0, NULL);
                        }
                    }
                    if (kq_events[i].filter & EVFILT_READ) { 
                        printf("read\n");
                        EV_SET(&kq_events[i], kq_events[i].ident, EVFILT_READ, EV_DISABLE, 0, 0, NULL);
                        EV_SET(&kq_events[i], kq_events[i].ident, EVFILT_WRITE, EV_ENABLE, 0, 0, NULL);
                        if (do_read(kq_events[i].ident) > 0 ) exit(0); // читаем и выходим
                    }
                }
            } else if (n < 0) {
                perror("kevent");
                break;
            }
        }

Но на деле получасется так, прога пишет более одного раза потом один раз читает и выходит, 
Почему не получается сразу читать после первой "записи", то есть не выключатся сокет на запись.

Код

rb: 76 
write
read
rb: 76
write
read
HTTP/1.1 200 OK
Server: nginx/0.6.10
Date: Fri, 18 Apr 2008 16:44:59 GMT
Content-Type: text/html; charset=koi8-r
Content-Length: 151
Last-Modified: Tue, 04 Mar 2008 15:30:17 GMT
Connection: keep-alive
Accept-Ranges: bytes

<html>
<head>
<title>Welcome to nginx!</title>
</head>
<body bgcolor="white" text="black">
<center><h1>Welcome to nginx!</h1></center>
</body>
</html>


Это сообщение отредактировал(а) fray - 18.4.2008, 19:50
PM MAIL   Вверх
kometa_75
Дата 21.4.2008, 08:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 62
Регистрация: 24.10.2007

Репутация: нет
Всего: нет



На самом деле при записи надо ещё некоторые вещи сделать. Посмотрите на код, ссылку на который я приводил. Ещё можно глянуть здесь - http://forums.ascentemu.com/ (эмулятор сервера ВоВ). У меня такой проблемы нет, поскольку я создаю событие только на чтение, соответственно с записью всё в порядке. Надеюсь, что это правильный подход.
PM MAIL   Вверх
fray
Дата 21.4.2008, 09:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 139
Регистрация: 7.6.2007

Репутация: нет
Всего: 0



Цитата(kometa_75 @ 21.4.2008,  08:50)
На самом деле при записи надо ещё некоторые вещи сделать. Посмотрите на код, ссылку на который я приводил. Ещё можно глянуть здесь - http://forums.ascentemu.com/ (эмулятор сервера ВоВ). У меня такой проблемы нет, поскольку я создаю событие только на чтение, соответственно с записью всё в порядке. Надеюсь, что это правильный подход.

с чекаутив это http://svn.inspircd.org/index.cgi/trunk/in...d/?pathrev=6557 и делая как в socketengine_kqueue.cpp 
Если я добовляю событие с на запись с флажками  EVFILT_WRITE, EV_ADD | EV_ONESHOT (line: 11 моего кода см.выше)
то получаю только так 

типа код
Код

int main() {
                size_t NEVENTS = 1;
                int fd[NEVENTS], kq;
                struct kevent kq_events[NEVENTS];
                init(&sa);

                if ( ( kq = kqueue() ) == -1 ) err(1,"%s:%i",__FILE__,__LINE__);

                struct timespec nullts = {1, 0};
                uint16_t i;
                for (i = 0; i< NEVENTS; i++) {
                        fd[i] = make_connect();
                        EV_SET(&kq_events[i], fd[i], EVFILT_WRITE, EV_ADD|EV_ONESHOT, 0, 0, NULL);
                        if (kevent(kq, &kq_events[i], 1, NULL, 0, &nullts) == -1 ) err(1,"%s:%i",__FILE__,__LINE__);
                }
                sleep(2);

                for (;;) {
                        int n = kevent(kq, NULL, 0, kq_events, NEVENTS, &nullts);
                        if (n > 0) {
                                for (i = 0; i < NEVENTS; i++) {
                                        if (kq_events[i].filter & EVFILT_WRITE) {
                                                if ( do_write(kq_events[i].ident) > 0 ) {
                                                        printf("write\n");
                                                        EV_SET(&kq_events[i], kq_events[i].ident, EVFILT_WRITE, EV_DELETE, 0, 0, NULL);
                                                        EV_SET(&kq_events[i], kq_events[i].ident, EVFILT_READ, EV_ADD, 0, 0, NULL);
                                                }
                                        }
                                        if (kq_events[i].filter & EVFILT_READ) {
                                                printf("read\n");
                                                if (do_read(kq_events[i].ident) > 0 ) { // не читает ?!?
                                                        printf("real-read\n"); // сюда уже не доходит 
                                                        EV_SET(&kq_events[i], kq_events[i].ident, EVFILT_READ, EV_DISABLE, 0, 0, NULL);
                                                        EV_SET(&kq_events[i], kq_events[i].ident, EVFILT_WRITE, EV_ENABLE, 0, 0, NULL);
                                                        exit(0);
                                                }
                                        }
                                }
                        } else if (n < 0) {
                                perror("kevent");
                                break;
                        }
                }
        return 0;
}



./prog
rb: 76
write
read

Писать начал только один раз, но перестал читать.  smile 
Если я удаляю добавление события на чтение, то это никак не влият на результат, 
вот так...
Код

               for (;;) {
                        int n = kevent(kq, NULL, 0, kq_events, NEVENTS, &nullts);
                        if (n > 0) {
                                for (i = 0; i < NEVENTS; i++) {
                                        if (kq_events[i].filter & EVFILT_WRITE) {
                                                if ( do_write(kq_events[i].ident) > 0 ) {
                                                        printf("write\n");
             //                                           EV_SET(&kq_events[i], kq_events[i].ident, EVFILT_WRITE, EV_DELETE, 0, 0, NULL);
              //                                          EV_SET(&kq_events[i], kq_events[i].ident, EVFILT_READ, EV_ADD, 0, 0, NULL);
                                                }
                                        }
                                        if (kq_events[i].filter & EVFILT_READ) {
                                                printf("read\n");
                                                if (do_read(kq_events[i].ident) > 0 ) { // не читает ?!?
                                                        printf("real-read\n"); // сюда уже не доходит 
                                                        EV_SET(&kq_events[i], kq_events[i].ident, EVFILT_READ, EV_DISABLE, 0, 0, NULL);
                                                        EV_SET(&kq_events[i], kq_events[i].ident, EVFILT_WRITE, EV_ENABLE, 0, 0, NULL);
                                                        exit(0);
                                                }
                                        }
                                }
                        } else if (n < 0) {
                                perror("kevent");
                                break;
                        }


Код

rb: 76 
write
read
rb: 76
write
read
HTTP/1.1 200 OK
Server: nginx/0.6.10
Date: Fri, 18 Apr 2008 16:44:59 GMT
Content-Type: text/html; charset=koi8-r
Content-Length: 151
Last-Modified: Tue, 04 Mar 2008 15:30:17 GMT
Connection: keep-alive
Accept-Ranges: bytes

<html>
<head>
<title>Welcome to nginx!</title>
</head>
<body bgcolor="white" text="black">
<center><h1>Welcome to nginx!</h1></center>
</body>
</html>

вот так, что за kqueue-бред что он сам добавляет события на чтение(в poll такого нет) ?  smile 

Это сообщение отредактировал(а) fray - 21.4.2008, 10:36
PM MAIL   Вверх
kometa_75
Дата 21.4.2008, 10:34 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 62
Регистрация: 24.10.2007

Репутация: нет
Всего: нет



Ваш код отличается, от того который в ссылках. Вы не так используете массив kq_events. Его надо использовать только при опросе сообщений(ну и при обработке, соответственно). Во всех остальных случаях надлежит использовать локальные экземпляры struct kevent.
Я не до конца понимаю, что должен делать ваш код. Смущают некоторые моменты, например вот это
Код

fd[i] = make_connect();


Это сообщение отредактировал(а) kometa_75 - 21.4.2008, 10:35
PM MAIL   Вверх
fray
Дата 21.4.2008, 10:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 139
Регистрация: 7.6.2007

Репутация: нет
Всего: 0



Цитата(kometa_75 @ 21.4.2008,  10:34)
Ваш код отличается, от того который в ссылках. Вы не так используете массив kq_events. Его надо использовать только при опросе сообщений(ну и при обработке, соответственно). Во всех остальных случаях надлежит использовать локальные экземпляры struct kevent.
Я не до конца понимаю, что должен делать ваш код. Смущают некоторые моменты, например вот это
Код

fd[i] = make_connect();

fd[i] = make_connect();
примерно выглядит так
int make_connect (void) {
   int sd = socket();
   if (fcntl(sd, F_SETFL, O_NONBLOCK) == -1) perror("fcntl");
   connect(sd);
   return sd;
}
конечно можно написать так
Код

int main() {
        size_t NEVENTS = 1;
        int kq;
        struct kevent kq_events[NEVENTS];
        struct kevent kq_events2[NEVENTS];

                if ( ( kq = kqueue() ) == -1 ) err(1,"%s:%i",__FILE__,__LINE__);

                struct timespec nullts = {1, 0};
                uint16_t i;
                for (i = 0; i< NEVENTS; i++) {
                        int fd = make_connect();
                        EV_SET(&kq_events[i], fd, EVFILT_WRITE, EV_ADD|EV_CLEAR, 0, 0, NULL);
                        if (kevent(kq, &kq_events[i], 1, NULL, 0, &nullts) == -1 ) err(1,"%s:%i",__FILE__,__LINE__);
                }
                sleep(2);

                for (;;) {
                        int n = kevent(kq, NULL, 0, kq_events2, NEVENTS, &nullts);
                        if (n > 0) {
                                for (i = 0; i < NEVENTS; i++) {
                                        if (kq_events2[i].filter & EVFILT_WRITE) {
                                                if ( do_write(kq_events2[i].ident) > 0 ) {
                                                        printf("write\n");
                                                        EV_SET(&kq_events[i], kq_events[i].ident, EVFILT_WRITE, EV_DELETE, 0, 0, NULL);
                                                        EV_SET(&kq_events[i], kq_events[i].ident, EVFILT_READ, EV_ADD, 0, 0, NULL);
                                                }
                                        }
                                        if (kq_events2[i].filter & EVFILT_READ) {
                                                printf("read\n");
                                                if (do_read(kq_events2[i].ident) > 0 ) {
                                                        printf("real-read\n");
                                                        EV_SET(&kq_events[i], kq_events2[i].ident, EVFILT_READ, EV_DISABLE,
 0, 0, NULL);
                                                        EV_SET(&kq_events[i], kq_events2[i].ident, EVFILT_WRITE, EV_ENABLE,
 0, 0, NULL);
                                                        exit(0);
                                                }
                                        }
                                }
                        } else if (n < 0) {
                                perror("kevent");
                         }


Добавлено через 5 минут и 37 секунд
Цитата(kometa_75 @  21.4.2008,  10:34 Найти цитируемый пост)
 Вы не так используете массив kq_events. Его надо использовать только при опросе сообщений(ну и при обработке, соответственно). Во всех остальных случаях надлежит использовать локальные экземпляры struct kevent.

А можно по подробней, что и не так делаю?

Это сообщение отредактировал(а) fray - 21.4.2008, 10:59
PM MAIL   Вверх
kometa_75
Дата 21.4.2008, 11:58 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 62
Регистрация: 24.10.2007

Репутация: нет
Всего: нет



Я так понял, что у вас обычное серверное приложение. Исходя из этого предположения, вот какой я написал код:
Код

int main()
 {
    size_t NEVENTS = 65535; // предположим, что будем иметь столько подключений
    int kq;
    struct kevent kq_events[NEVENTS]; // здесь будут наши события
    struct timespec nullts = {1, 0};
    int listen_socket; // на него будут коннектится клиенты

     if ( ( kq = kqueue() ) == -1 ) err(1,"%s:%i",__FILE__,__LINE__); // создаём дескриптор

     listen_socket = make_listen_socket(); // создаём слушающий сокет
     // определяем для него событие
     struct kevent ke;
     EV_SET(&ke, listen_socket, EVFILT_READ, EV_ADD, 0, 0, NULL);
     if(kevent(kq, &ke, 1, 0, 0, NULL) == -1) perror("kevent()");
               
     for (;;) 
     {
        int n = kevent(kq, NULL, 0, &kq_events[0], NEVENTS, &nullts);
        if (n < 0) 
        {
          perror("kevent");
          exit(0);
         }
        else if (n > 0) 
        {
           for (i = 0; i < n; i++) 
           {
             if(ke_list[i].ident == listen_socket) // если кто-то подключился
             {
               int new_connect = make_connect(); // подключаем
               struct kevent ke;
               EV_SET(&ke, new_connect, EVFILT_READ, EV_ADD, 0, 0, NULL);
               if(kevent(kq, &ke, 1, 0, 0, NULL) == -1) perror("kevent()");   
             }
             // клиент отключился 
             if(kq_events[i].flags & EV_EOF || kq_events[i].flags & EV_ERROR )
             {
               printf("remove connect %d\n", kq_events[i].ident);
               struct kevent ke;
               EV_SET(&ke, kq_events[i].ident, EVFILT_READ, EV_DELETE, 0, 0, NULL);
               if(kevent(kq, &ke, 1, 0, 0, NULL) < 0) perror("kevent()");
               close(kq_events[i].ident); // я рекомендую удалять
             }

             if (kq_events[i].filter == EVFILT_WRITE) // в этом коде - бесполезно
             {
               printf("write\n");
              }
             else if (kq_events[i].filter == EVFILT_READ) 
             {
               printf("read\n");
               // обрабатываем ввод...
              }
            }
          }
         }


Эта модель у меня работает. Если хотите "автоматизировать" ещё и отправку данных, то необходимо ещё создавать событие на запись, и после каждой обработки события определять событие для записи. Я этого не делал, поскольку сам контролирую процесс отправки данных.

Это сообщение отредактировал(а) kometa_75 - 21.4.2008, 12:17
PM MAIL   Вверх
fray
  Дата 21.4.2008, 15:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 139
Регистрация: 7.6.2007

Репутация: нет
Всего: 0



Цитата(kometa_75 @  21.4.2008,  11:58 Найти цитируемый пост)
что у вас обычное серверное приложение. 

Не наоборот у меня клиент. И проблема вырисовалась так - почему когда я добавил мониторить событие на запись у меня присутсвует событие и чтение, почему когда я удалил событие на запись оно осталось ?

Последний вариант выглядит так.

Код

int main() {
        size_t NEVENTS = 1;
        int kq;
        struct kevent kq_events[NEVENTS];
        struct kevent kq_change[NEVENTS];
        init(&sa);

        if ( ( kq = kqueue() ) == -1 ) err(1,"%s:%i",__FILE__,__LINE__);

        struct timespec ts = {0,1000};
        uint16_t i;
        for (i = 0; i< NEVENTS; i++) {
            int fd = make_connect();
            EV_SET(&kq_change[i], fd, EVFILT_WRITE, EV_ADD | EV_ENABLE, 0, 0, NULL);
        }
        sleep(1);

        for (;;) {
            int n = kevent(kq, kq_change, NEVENTS, kq_events, NEVENTS, &ts);
            if (n > 0) {
                for (i = 0; i < n; i++) {
                    if (kq_events[i].filter == EVFILT_WRITE) {
                        if ( do_write(kq_events[i].ident) > 0 ) {
                            printf("write\n");
                            EV_SET(&kq_events[i], kq_events[i].ident, EVFILT_WRITE, EV_DELETE, 0, 0, NULL);
                            EV_SET(&kq_events[i], kq_events[i].ident, EVFILT_READ, EV_ADD, 0, 0, NULL);
                        }
                    }
                    if (kq_events[i].filter == EVFILT_READ) {
                        printf("read\n");
                        if (do_read(kq_events[i].ident) > 0 ) {
                            EV_SET(&kq_events[i], kq_events[i].ident, EVFILT_READ, EV_DISABLE, 0, 0, NULL);
                            EV_SET(&kq_events[i], kq_events[i].ident, EVFILT_WRITE, EV_ENABLE, 0, 0, NULL);
                            exit(0);
                        }
                    }
                }
            } else if (n < 0) {
                perror("kevent");
                break;
            }
        }
        return 0;
}


Я хочу чтобы клиент по очереди читал потом писал и так далее..., но событие не удаляется ( EV_SET(&kq_events[i], kq_events[i].ident, EVFILT_WRITE, EV_DELETE, 0, 0, NULL);) и продолжает писать, пишит несколько раз,
а мне хотелось чтобы прога работала написал-прочитал.

а у меня по запуску выдает это, то есть получается что флажки на запись и чтение подняты ссамого начала.
(rb: - сколько байт мы отправили)
Код

rb: 76
write
read
rb: 76
write
read
rb: 76
write
read
rb: 76
write
read
rb: 76
write
read
rb: 76
write
read
HTTP/1.1 200 OK
Server: nginx/0.6.10
Date: Mon, 21 Apr 2008 12:01:21 GMT
Content-Type: text/html; charset=koi8-r
Content-Length: 151
Last-Modified: Tue, 04 Mar 2008 15:30:17 GMT
Connection: keep-alive
Accept-Ranges: bytes

<html>
<head>
<title>Welcome to nginx!</title>
</head>
<body bgcolor="white" text="black">
<center><h1>Welcome to nginx!</h1></center>
</body>
</html>


хотя как мне кажется ответ должен быть таким...

Код

rb: 76
write
read

HTTP/1.1 200 OK
Server: nginx/0.6.10
Date: Mon, 21 Apr 2008 12:01:21 GMT
Content-Type: text/html; charset=koi8-r
Content-Length: 151
Last-Modified: Tue, 04 Mar 2008 15:30:17 GMT
Connection: keep-alive
Accept-Ranges: bytes

<html>
<head>
<title>Welcome to nginx!</title>
</head>
<body bgcolor="white" text="black">
<center><h1>Welcome to nginx!</h1></center>
</body>
</html>


Это сообщение отредактировал(а) fray - 21.4.2008, 15:13
PM MAIL   Вверх
kometa_75
Дата 21.4.2008, 15:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 62
Регистрация: 24.10.2007

Репутация: нет
Всего: нет



По-моему, в вашем случае должно быть примерно так:
Код

int main()
 {
    size_t NEVENTS = 65535; // предположим, что будем иметь столько подключений
    int kq;
    struct kevent kq_events[NEVENTS]; // здесь будут наши события
    struct timespec nullts = {1, 0};

     if ( ( kq = kqueue() ) == -1 ) err(1,"%s:%i",__FILE__,__LINE__); // создаём дескриптор

    for (i = 0; i< NEVENTS; i++) 
    {
        int fd = make_connect();
        struct kevent ke;
        EV_SET(&ke, fd, EVFILT_READ, EV_ADD, 0, 0, NULL);
        if(kevent(kq, &ke, 1, 0, 0, NULL) == -1) perror("kevent()");   
    }
     
     for (;;) 
     {
        int n = kevent(kq, NULL, 0, &kq_events[0], NEVENTS, &nullts);
        if (n < 0) 
        {
          perror("kevent");
          exit(0);
         }
        else if (n > 0) 
        {
           for (i = 0; i < n; i++) 
           {
             if (kq_events[i].filter == EVFILT_WRITE)
             {
               printf("write\n");
               do_write(kq_events[i].ident);

               struct kevent ke;
               EV_SET(&ke, fd, EVFILT_READ, EV_ADD, 0, 0, NULL);
               if(kevent(kq, &ke, 1, 0, 0, NULL) == -1) perror("kevent()");   
              }
             else if (kq_events[i].filter == EVFILT_READ) 
             {
               printf("read\n");
               do_read(kq_events[i].ident);

               struct kevent ke;
               EV_SET(&ke, fd, EVFILT_WRITE, EV_ADD | EV_ONESHOT, 0, 0, NULL);
               if(kevent(kq, &ke, 1, 0, 0, NULL) == -1) perror("kevent()");    
              }
            }
          }
         }

PM MAIL   Вверх
fray
Дата 21.4.2008, 18:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 139
Регистрация: 7.6.2007

Репутация: нет
Всего: 0



Цитата(kometa_75 @  21.4.2008,  15:41 Найти цитируемый пост)
struct kevent ke;

А зачем создавать новые структуры, не ужели нельзя все варить в kq_events, как делатьеся например в poll ?

PM MAIL   Вверх
kometa_75
Дата 22.4.2008, 08:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 62
Регистрация: 24.10.2007

Репутация: нет
Всего: нет



Цитата(fray @  21.4.2008,  18:33 Найти цитируемый пост)
А зачем создавать новые структуры, не ужели нельзя все варить в kq_events, как делатьеся например в poll ?

Меня это тоже интересует, однако так делается в примерах рабочего кода, а подход с двумя массивами у меня тоже не работает. Кстати, с epoll я также работаю через локальные экземпляры struct epoll_event, и ничего, нормально всё.
Ну а как ваш код, заработал ?

PM MAIL   Вверх
fray
  Дата 23.4.2008, 11:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 139
Регистрация: 7.6.2007

Репутация: нет
Всего: 0



Цитата(kometa_75 @  22.4.2008,  08:50 Найти цитируемый пост)
Меня это тоже интересует, однако так делается в примерах рабочего кода, а подход с двумя массивами у меня тоже не работает. Кстати, с epoll я также работаю через локальные экземпляры struct epoll_event, и ничего, нормально всё.
Ну а как ваш код, заработал ?

Нет не заработал, просто нигде не могу найти пример клиента на основе kqueue, одни серверы, просто пытаюсь сделать как у них(freebsd) описано тут http://people.freebsd.org/~jlemon/papers/kqueue.pdf  на странице 6 стравнение с poll, на роll'e уменя все работает, вот тоже самое на kqueue нет  smile 
PM MAIL   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С/С++: Программирование под Unix/Linux"
xvr
  • Проставьте несколько ключевых слов темы, чтобы её можно было легче найти.
  • Не забывайте пользоваться кнопкой "Код".
  • Вопросы мобильной разработки тут
  • Телепатов на форуме нет! Задавайте чёткий, конкретный и полный вопрос. Указывайте полностью ошибки компилятора и компоновщика.
  • Новое сообщение должно иметь прямое отношение к разделу форума. Флуд, флейм, оффтопик запрещены.
  • Категорически запрещается обсуждение вареза, "кряков", взлома программ и т.д.

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, xvr.

 
 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Программирование под Unix/Linux | Следующая тема »


 




[ Время генерации скрипта: 0.1344 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.