Model sterowany zdarzeniami w C

Jestem naprawdę zainteresowany programowaniem sterowanym zdarzeniami w C, szczególnie z gniazdami, więc zamierzam poświęcić trochę czasu na moje badania.

Załóżmy, że chcę zbudować program z dużą ilością plików i sieci We/Wy, jak aplikacja klient / serwer, w zasadzie pierwsze pytanie brzmi, jaka jest filozofia tego modelu. Podczas gdy w normalnym programowaniu generowałbym nowe procesy, jak to możliwe, że pojedynczy proces może faktycznie obsługiwać wiele innych żądań. Na przykład istnieje kilka serwerów internetowych który może obsługiwać połączenia bez tworzenia wątków lub innych procesów, tylko jeden główny proces.

Wiem, że to skomplikowane, ale zawsze miło jest przynajmniej wiedzieć, jak wygląda Infrastruktura tego rodzaju programowania.

Author: 象嘉道, 2012-06-16

5 answers

Koniecznie musisz przeczytać: http://www.kegel.com/c10k.html . Ta strona jest doskonałym przeglądem technik asynchronicznych i sterowanych zdarzeniami.

Jednak szybka i brudna ODPOWIEDŹ : sterowane zdarzeniami nie jest ani nieblokujące, ani asynchroniczne.

Event-driven oznacza, że proces będzie monitorował swoje deskryptory plików (i gniazda) i działał tylko wtedy, gdy na jakimś deskryptorze wystąpi jakieś zdarzenie (zdarzenia to: data received, error, became writable, ...).

Gniazda BSD posiadają funkcję " select ()". Po wywołaniu system operacyjny będzie monitorować deskryptory i powróci do procesu, gdy tylko wystąpi jakieś zdarzenie na jednym z deskryptorów.

Jednak powyższa strona ma znacznie lepsze opisy (i szczegóły dotyczące różnych API).

 17
Author: Frunsi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-06-16 12:26:36

"Jaka jest filozofia stojąca za tym modelem"

Event driven oznacza, że nie ma "monitorowania", ale że samo zdarzenie inicjuje akcję.

Zazwyczaj inicjowane jest przez przerwanie, które jest sygnałem do systemu z urządzenia zewnętrznego lub (w przypadku przerwania programowego) procesem asynchronicznym.

Https://en.wikipedia.org/wiki/Interrupt

Czytaj dalej tutaj:

Https://docs.oracle.com/cd/E19455-01/806-1017/6jab5di2m/index.html#sockets-40 - "Interrupt-Driven Socket I / O"

Również http://cs.baylor.edu / ~donahoo/practical/CSockets/textcode.html zawiera kilka przykładów gniazd sterowanych przerwaniami, jak również inne przykłady programowania gniazd.

 2
Author: Graham,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-08-14 13:01:49

Programowanie sterowane zdarzeniami opiera się na pętli zdarzeń. Pętla po prostu czeka na nowe zdarzenie, wysyła kod do obsługi zdarzenia, a następnie zapętla z powrotem, aby poczekać na następne zdarzenie. W przypadku gniazd mówimy o "asynchronicznym programowaniu sieci". Wymaga to select () lub innej opcji, takiej jak Kqueue (), aby czekać na zdarzenia w pętli zdarzeń. Sockety muszą być ustawione na non blocking , aby podczas odczytu() lub zapisu () Twój kod nie czekał na I / O do zakończenia.

Asynchroniczne programowanie sieciowe może być bardzo skomplikowane i trudne. Zobacz kilka wstępów tutaj i tutaj . Zdecydowanie sugeruję użycie biblioteki, takiej jak libevent lub liboop , aby to naprawić.

 1
Author: Matt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-06-16 12:30:10

Tego rodzaju Serwery/klienci TCP mogą być zaimplementowane za pomocą select(2) połączeń i nieblokujących gniazd.

[5]} trudniej jest używać gniazd nieblokujących niż gniazd blokujących.

Przykład:

connect wywołanie zwykle zwraca natychmiast -1 i ustawia errno EINPROGRESS, Gdy używane są gniazda nieblokujące. W takim przypadku należy użyć select, aby poczekać na otwarcie lub niepowodzenie połączenia. connect może również zwrócić 0. Może się to zdarzyć, jeśli utworzysz połączenie z lokalnym hostem. W ten sposób możesz obsługiwać inne gniazda, podczas gdy jedno gniazdo otwiera połączenie TCP.

 1
Author: SKi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-06-20 10:13:36

To bardzo specyficzne dla platformy, jak to działa.

Jeśli Twoje działanie na Linuksie nie jest takie trudne, po prostu musisz wywołać kopię swojego procesu za pomocą 'forka', coś w stylu:

#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <netinet.h>
#include <signal.h>
#include <unistd.h>

int main()
{
  int server_sockfd, client_sockfd;
  int server_len, client_len;
  struct sockaddr_in server_address;
  struct sockaddr_in client_address;

  server_sockfd = socket(AF_INET, SOCK_STREAM, 0);

  server_address.sin_family = AF_INET;
  server_address.sin_addr.s_addr = htonl(INADDR_ANY);
  server_Address.sin_port = htons(1234);
  server_len = sizeof(server_address);
  bind(server_sockfd, (struct sockaddr *)&server_address, server_len);

  listen(server_sockfd, 5);

  signal(SIGCHLD, SIG_IGN);

  while(1)
  {
    char ch;
    printf("Server Waiting\n");
    client_len = sizeof(client_address);
    client_sockfd = accept(server_sockfd, (struct sockaddr *)&client_address, &client_len)

    // Here's where we do the forking, if you've forked already then this will be the child running, if not then your still the parent task.

    if(fork() == 0)
    {
      // Do what ever the child needs to do with the connected client
      read(client_sockfd, &ch, 1);
      sleep(5); // just for show :-)
      ch++;
      write(client_sockfd, &ch, 1);
      close(client_sockfd);
      exit(0);
    }
    else
    {
      // Parent code here, close and loop for next connection
      close(client_sockfd);
    }
  }
}

Być może będziesz musiał trochę pogrywać z tym kodem nie jestem w pobliżu Linuksa w tej chwili, aby zrobić testową kompilację, a ja prawie wpisałem go z pamięci.

Używanie forka jest jednak standardowym sposobem na to w C pod system oparty na systemie Linux / Unix.

Pod windows To zupełnie inna historia, i taka, której nie pamiętam cały kod potrzebny (jestem sposób, aby przyzwyczaić się do kodowania w C# te dni), ale konfiguracja gniazda jest prawie tak samo, z wyjątkiem trzeba użyć 'Winsock' API dla lepszej kompatybilności.

Można (i tak uważam) nadal używać standardowych gniazd pod windows, ale jest to pełne pułapek i dziur, dla windows winsock jest to dobre miejsce na początek:

Http://tangentsoft.net/wskfaq/

O ile mi wiadomo, jeśli używasz Winsocka to ma coś do pomocy przy spawaniu i multi kliencie, osobiście jednak zwykle po prostu wyłączam oddzielny wątek i kopiuję do niego połączenie z gniazdem, a następnie wracam do pętli słuchając mojego serwera.

 0
Author: shawty,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-06-16 11:13:08