anonymous
написал 5 августа 2005 года в 15:25 (816 просмотров)
Ведет себя
неопределенно; открыл 1814 темы в форуме, оставил 5575 комментариев на сайте.
Приветствую.
Изучаю написание сетевого демона под линукс. Сейчас мой демон имеет структуру:
…
sd = socket();
bind(sd, … );
if ( listen(sd, 5) == -1)
{ … }
for (;;) {
ns = accept(sd, …);
pid=fork();
if (pid == 0) /* child */
{
close(sd);
…
recv();
…
close(ns);
exit(0); /* exit status of child */
}
close(ns); /* parent */
}
Вопрос такой: при этой архитектуре будут ли у демона серьезные ограничения по числу одновременно обрабатываемых запросов? Если да, то что нужно менять в структуре приложения? Поможет ли здесь select()/poll() ?
Спасибо!
Последние комментарии
-
OlegL, 17 декабря 2023 года в 15:00 →
Перекличка
21
-
REDkiy, 8 июня 2023 года в 9:09 →
Как «замокать» файл для юниттеста в Python?
2
-
fhunter, 29 ноября 2022 года в 2:09 →
Проблема с NO_PUBKEY: как получить GPG-ключ и добавить его в базу apt?
6
-
Иванн, 9 апреля 2022 года в 8:31 →
Ассоциация РАСПО провела первое учредительное собрание
1
-
Kiri11.ADV1, 7 марта 2021 года в 12:01 →
Логи catalina.out в TomCat 9 в формате JSON
1
DevOps as a Service from Palark
24/7 SRE & DevOps service to cover all your Kubernetes needs.

Будут ограничения по памяти (см. описание fork()).
Вот select() помочь может, poll() в этом случае хуже.
Можно посмотреть в сторону pthread.
селект маздай :)
roman_m по такому принципу как у тебя — это так устроен апач первый (он создает тучу процессов, каждый обслуживает отдельного клиента). Второй апач создает процесс, в каждом процессе сколько-то потоков (прописывается в конфиге), а уже потоки обслуживают клиентов. У меня (в недописанном еще HTTP сервере Flexer, который я забросил уже писать ибо работа и учеба) как раз используется такой же вариант. Только там все хитрее, создается пул процессов и потоков (чтоб не тратить потом время на их создание отдельно), когда появляется клиент новый — то его данные передаются свободному процессу/потоку из пула.
Ага, но это смотря зачем, а точнее как этот select пользуется. Пока потоков не слишком много, то действительно лучше потоки, по всем параметрам (простота кода, безопасность за счёт _attribute__((__thread_local_)), быть может, скорость). А когда количество потоков/процессов становится достаточно большим, то ядро начинает притормаживать — ему же надо регулярно приоритеты пересчитывать для всех потоков/процессов, есть и другие куски ядра, время выполнения которых прямо пропорционально количеству задач. То есть, если это апач, у которого не так много одновременно живущих соединений и на каждое соединение надо запускать php интерпретатор, или там cgi процесс — то это один вариант. А ежели irc сервер, в котором соединений может быть пара тысяч и при этом работа с отдельно взятым соединением проста, то уж лучше select, и, может быть, переадресация запроса другому потоку/процессу, если, конечно, хочется многопроцессорность пользовать.
Где-то я какой-то фак читал (может из pthread?), там был подобный вопрос, и рекомендации были такие: пускай будет один поток, который listen, и пачка, которые select. Там речь шла именно о тысячах соединений.
ЗЫ какой attribute прикольный стал :)
Правильно сказали смотри в сторону нитей. Создавай для кажого соеденения отсоедененную нить. Вот пример накидал. Есть желание посмотри может поможет чем
#include #include #include #include #include #include #include #include #include #define HOSTLEN 256 #define BACKLOG 1 int server_bind(int port, int back) { struct sockaddr_in sock; struct hostent *hp; char hostname[HOSTLEN]; int fd; fd = socket(AF_INET,SOCK_STREAM,0); if(fd <0){ perror("socket"); return -1; } memset(&sock,0,sizeof(struct sockaddr)); gethostname(hostname,HOSTLEN); hp=gethostbyname(hostname); bcopy((void *)hp->h_addr,(void *)&sock.sin_addr,hp->h_length); sock.sin_port = htons(port); sock.sin_family = AF_INET; // saddr.sin_addr.s_addr=htonl(INADDR_ANY); if(bind(fd,(struct sockaddr *)&sock,sizeof(struct sockaddr)) !=0) { perror("Bind"); return -1; } if(listen(fd,back) != 0) { perror("listen"); return -1; } return fd; } setup(pthread_attr_t *attrp) { pthread_attr_init(attrp); pthread_attr_setdetachstate(attrp,PTHREAD_CREATE_DETACHED); } void *h_call(void *fdptr) { FILE *fp; char request[BUFSIZ]; int fd,c; fd = *(int *)fdptr; free(fdptr); fp = fdopen(fd,"r+"); while(1){ fgets(request,BUFSIZ,fp); fprintf(stderr,"got a call on %d: request = %s\n",fd,request); fprintf(fp,"YOU SEND: %s\n",request); } fclose(fp); } main(int argc, char *argv[]) { int sock,fd; int *fdptr; pthread_t work; pthread_attr_t attr; if(argc == 1) { fprintf(stderr,"USAGE: serv port\n"); exit(1); } sock = server_bind(atoi(argv[1]),BACKLOG); if (sock == -1) { perror("making socket"); exit(2); } setup(&attr); while(1) { fd = accept(sock,NULL,NULL); fdptr = (int *)malloc(sizeof(int)); *fdptr = fd; pthread_create(&work,&attr,h_call,fdptr); } }Спасибо за ответы.
Касательно тредов — в других конференциях писали, что треды хорошо реализованы в ядре 2.6, я же жестко привязан только к ядру 2.4.18, возможны грабли?
И второе — в моем демоне обслуживание одного соединения не должно (теоретически :) ) занимать более 1сек., быть может форки не так сильно и навредят?
Попробуй треды и форки. Погоняй и посмотри что лучше.
глянь сюда ещё http://httpd.apache.org/docs/2.0/ru/misc/perf-tuning.html — полезно знать (особенно секция «accept Serialization — multiple sockets»).
http://cebka.pp.ru/mywiki/ru%2eunix%2eprog%2eservers%2efaq