Автор Тема: Задача 2 - 10.09 - 16.09 - quotes web service  (Прочетена 133446 пъти)

gat3way

  • Напреднали
  • *****
  • Публикации: 6050
  • Relentless troll
    • Профил
    • WWW
Задача 2 - 10.09 - 16.09 - quotes web service
« Отговор #15 -: Sep 18, 2007, 15:54 »
Ъммм, замалко да изтърва срока бе '<img'>

Ето я моята бъглива тъпотия:

Цитат

// blablabla
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/epoll.h>
#include <errno.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <pthread.h>
#include <stdlib.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/stat.h>
#include <string.h>


// port to listen to, connection limit, maximum number of threads
#define PORT 1800
#define MAXCONN 100
#define MAXTHREADS 10
#define MAXBUF 20000 //socket buffer size

// external program
char *EXTERNAL_BIN="/usr/games/fortune";

int sd=-1; // listening socketfd

// connection table
struct contable
{
    int fd; //filedes
    unsigned long peer; //peer inet addr, unused
    char *buf; // socket buffer
    char *buf1; // mini socket buffer '<img'>
} *ctab[MAXCONN];

int cti=1; //global connection count


// threads struct table
struct thstable
{
    int epfd; // epoll fd
    pthread_t pth; //thread
    int lock; // a primitive lock - unused
} ttab[MAXTHREADS];

int tti=MAXTHREADS; // the number of spawned threads (by default=MAXTHREADS)
struct epoll_event *ev[MAXTHREADS]; //epoll events


// remove connection from table
void conn_remove(int id, int tid)
{
    if (cti==1) {}
    if (cti>=2)
    {

// delete from events pool, close socket
        ev[tid]->events = EPOLLIN | EPOLLPRI | EPOLLERR | EPOLLHUP;
        epoll_ctl(ttab[tid].epfd,EPOLL_CTL_DEL,ctab[id]->fd, ev[tid] );
        close(ctab[id]->fd);
#ifdef DEBUG
        printf("Client fd #%d closing connection,cti=%d\n",ctab[id]->fd,cti);
#endif

//table-related bs
        ctab[id]->fd=ctab[cti]->fd;
        strcpy(ctab[id]->buf,ctab[cti]->buf);
        bzero(ctab[cti]->buf,MAXBUF);
        cti--;
    }
}


// parse request - very lame
void parse(int id, int tid)
{
    char *str=malloc(150);
    char *str1=malloc(150);
    char *buf=malloc(1024);
    FILE *outp;
    int a=0;
    pid_t pid;

// VERY VERY LAME!!!
    if ( strstr(ctab[id]->buf,"\r\n") )
        if ( (strstr(ctab[id]->buf,"text/html")) || (strstr(ctab[id]->buf,"text/html")) || (strstr(cta
b[id]->buf,"text/html")))
        {
            sprintf(str,"/var/tmp/mypr-np-%d",id);
            outp=fopen(str,"r");
            a=1;
            sprintf(str1,"%s > %s",EXTERNAL_BIN,str);

            sprintf(buf,"HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n<html><head><title>%s output</title></head><body><center><b><h2>%s output:</center></h2><br><br><center><table height=100% width=
100%><tr align=center valign=top><td><table height=50% width=50% border=1><tr valign=middle align=cent
er><td bgcolor=lightyellow>\n",EXTERNAL_BIN,EXTERNAL_BIN);
            write(ctab[id]->fd,buf,strlen(buf));
            system(str1);
            usleep(1000);
            while (feof(outp)==0)
            {
                if (fgets(buf,1024,outp))
                {
                    write(ctab[id]->fd,buf,strlen(buf));
                }
            }
            close(outp);
            sprintf(buf,"</td></tr></table></td></tr></table></body></html>\n");

            conn_remove(id,tid);
        }

    free(buf);free(str);free(str1);
}


// this actually performs the socket I/O
void serve(int fd, int tid)
{
    int len,a;
    int id=0;

    // find our conntab entry
    for (a=1;a<=cti;a++) if (ctab[a]->fd==fd) id=a;
    if (id==0) {printf("Socket error?!?\n");exit(1);}
    bzero(ctab[id]->buf1,MAXBUF/10);
    // read from socket
    for (a=1;a<=100;a++)
    {
        len=read(fd,ctab[id]->buf1,MAXBUF/10);
        if (len>0) goto cont;
        usleep(1000);
    }
    cont:
    if (len>0)
    {
        strcat(ctab[id]->buf,ctab[id]->buf1);
        parse(id,tid);
    }
    // socket closed?
    if (len==0)
    {
        conn_remove(id,tid);
    }

}

// wait for socket event and transfer it to serve()
void workthread(int num)
{
    int nfds,a,b,fd;

    while (1)
    {
        out:
        nfds  = epoll_wait(ttab[num].epfd, ev[num],tti,1);
        usleep(5000);
        if (nfds < 0) {
#ifdef DEBUG
            printf("Epoll confusion, LOL! '<img'>\n");
#endif
            goto out;
        }
        for (a=1;a<=nfds;a++)
        {
            fd=ev[num]->data.fd;
            if (fd>0) serve(fd,num);
        }
    }
}


// Another thread designed to terminate incoming connections
void listener_thread(void *arg)
{

    int a=1;
    struct timeval tv;
    int len,client;
    struct sockaddr_in addr;
    int addrlen = sizeof(addr);
    int flags;

    while (1)
    {
// sleep a little
        usleep(5000);

// accept connection. fd>=4 means most certainly this is a socket fd
        client = accept(sd, (struct sockaddr*)&addr, &addrlen);
        if ((client>=4)&&(addrlen>0))
        {

// socket timeouts setting
            tv.tv_usec=5;
            tv.tv_sec=0;
            setsockopt( client, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv) );

// make the newly accepted socket non-blocking..
            if ((flags = fcntl(client, F_GETFL, 0)) < 0)
            {
                perror("fcntl");
            }
            if (fcntl(client, F_SETFL, flags | O_NONBLOCK) < 0)
            {
                perror("fcntl");
            }

#ifdef DEBUG
            printf("Connected: %s:%d\n", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
#endif
            if (cti == MAXCONN) {close(client);} // EXAMPLE OF BAD CONNECTION LIMIT HANDLING!!!
            else
            {
// tables & epoll bs
                if (cti>1) cti++;
                a++;
                if (a==tti) a=1;
                ctab[cti]->fd=client;
                ctab[cti]->peer=addr.sin_addr.s_addr;
                ev[a]->events = EPOLLIN | EPOLLPRI | EPOLLERR | EPOLLHUP;
                ev[a]->data.fd=client;
                epoll_ctl(ttab[a].epfd,EPOLL_CTL_ADD,client, ev[a] );
                if (cti==1) cti++;
            }
        }
    }
}


// main function
int main()
{

// socket-related vars
    struct sockaddr_in addr;
    int addrlen = sizeof(addr);
    int flags;
    struct timeval tv;
    int len,client,a;
// listener thread
    pthread_t listener;

    printf("server starting..\n");
// SIGPIPE suck in a threaded app '<img'>
    signal( SIGPIPE , SIG_IGN );
// Init Serversocket
    if ( (sd = socket(PF_INET, SOCK_STREAM, 0)) < 0 ) perror("Socket");
    flags=1;
// Socket is to be reused (avoid stupid bind:already in use errors)
    setsockopt( sd, SOL_SOCKET, SO_REUSEADDR, &flags, sizeof(flags) );
// bind(), listen()
    addr.sin_family = AF_INET;
    addr.sin_port = htons(PORT);
    addr.sin_addr.s_addr = INADDR_ANY;

    if ( bind(sd, (struct sockaddr*)&addr, addrlen) < 0 ) {perror("bind");abort();}
    if ( listen(sd, MAXCONN) < 0 ) perror("listen");
// non-blocking server socket
    if ((flags = fcntl(sd, F_GETFL, 0)) < 0)
    {
        perror("fcntl");
    }

    if (fcntl(sd, F_SETFL, flags | O_NONBLOCK) < 0)
    {
        perror("fcntl");
    }
    printf("init threads");
// Init worker threads..
    for (a=1;a<=tti;a++)
    {
        ev[a]=malloc(300);
        pthread_create(&ttab[a].pth, NULL, workthread, a);
        ttab[a].epfd=epoll_create(MAXCONN/tti);
        ttab[a].lock=ttab[a].lock=0;
        printf(".");
    }
    printf("OK!\n");

// Init listener thread
    pthread_create(&listener, NULL, listener_thread,"");

// Init connection table..
    for (a=1;a<=MAXCONN;a++)
    {
        ctab[a]=malloc(sizeof(int)*4);
        ctab[a]->buf=malloc(MAXBUF);
        bzero(ctab[a]->buf,MAXBUF);
        ctab[a]->buf1=malloc(MAXBUF/10);
        bzero(ctab[a]->buf1,MAXBUF/10);
        ctab[a]->fd=0;
    }

// wait for listener thread to finish..
    pthread_join(listener,NULL);
    return 0;
}



Значи принципно е threaded и използва epoll, за да си се занимава със сокетите. Не се форк-ва отделен процес за всяка конекция (обаче това не е точно така с оглед на това, че се вика външна програма). Би следвало да е бързичко, пестеливо откъм ползване на РАМ и в тоя ред на мисли, да държи повече едновременни конекции, само дето не знам дали е така.

Дотук с хубавите неща '<img'> Това е най-малоумната многонишкова програма, която съм писал (добре де, на второ място след една друга подобна). Не съм се замислял особено, но на теория е напълно възможно при повечко едновременно работещи нишки да се случат лоши неща и програмата да се сбъгяса или крашне (например да се опита да изпише резултата вместо където трябва, в току-що затворен сокет '<img'> ). Отделно, parse-ването на заявката е левашко и глупаво.

И накрая, програмата използва libpthread (компилира се с флаг -lpthread) . Използва epoll като механизъм за poll-ване на сокетите за нови събития. Това е много хубаво нещо, само дето съществува от 2.6 насам, за всички със стари ядра, съжалявам, няма как да го компилирате '<img'>  Идеята е една нишка или процес да може да сервира някакъв брой конекции едновременно, да не се налага да се форк-ват нови такива за всяка нова, защото това е огромно разхищение. За да стане това, има два варианта за poll-ване на сокетите - select() и epoll_wait(). select е по-универсален, но се базира на обхождане на един свързан списък, и е доказано тромав '<img'> Важното при тоя подход обаче е сокетите да са non-blocking, в противен случай занятието придобива малко идиотски измерения '<img'>
Активен

"Knowledge is power" - France is Bacon

BULFON

  • Administrator
  • Напреднали
  • *****
  • Публикации: 478
  • Distribution: Fedora
  • Window Manager: Gnome
    • Профил
Задача 2 - 10.09 - 16.09 - quotes web service
« Отговор #16 -: Sep 18, 2007, 17:55 »
А къде искате да се видим утре в 19.30?
Активен

фонокартен телефонен апарат

VladSun

  • Moderator
  • Напреднали
  • *****
  • Публикации: 2166
    • Профил
Задача 2 - 10.09 - 16.09 - quotes web service
« Отговор #17 -: Sep 18, 2007, 17:59 »
Цитат (BULFON @ Сеп. 18 2007,17:55)
А къде искате да се видим утре в 19.30?

Аз мислех, че вече е уговорено ... както обикновено - в "Кривото" на ул. Будапеща?

Ама, ако решите нещо друго - няма проблеми '<img'>
Активен

KISS Principle ( Keep-It-Short-and-Simple )
http://openfmi.net/projects/flattc/
Има 10 вида хора на този свят - разбиращи двоичния код и тези, които не го разбират :P

tarator

  • Напреднали
  • *****
  • Публикации: 849
    • Профил
Задача 2 - 10.09 - 16.09 - quotes web service
« Отговор #18 -: Sep 18, 2007, 18:32 »
Забелязвам сериозен overdesign и в двете решения на C. Keep it simple, stupid.
Активен

A gentleman is one who is never rude unintentionally. - Noel Coward

gat3way

  • Напреднали
  • *****
  • Публикации: 6050
  • Relentless troll
    • Профил
    • WWW
Задача 2 - 10.09 - 16.09 - quotes web service
« Отговор #19 -: Sep 18, 2007, 18:40 »
yup, KISS е хубав принцип, ама когато си си планирал нещата като хората. За има-няма половин ден занимания, толкова. Както вече споделих с един друг участник '<img'> на средата вече псувах много лошо задето съм се захванал да правя тая глупост по тоя начин.Нещо се бях обсебил от няколко идеи, добре че изтърпях до края '<img'>
Активен

"Knowledge is power" - France is Bacon

tarator

  • Напреднали
  • *****
  • Публикации: 849
    • Профил
Задача 2 - 10.09 - 16.09 - quotes web service
« Отговор #20 -: Sep 18, 2007, 19:14 »
gateway,

Например процес (или ако много държиш тред) за връзка опростява много решението без да е ужасно неефективно. Все пак това е задача, не код за production, най-важното е прегледността, а не оптимизацията.

Има един програмист дето разправя, че твърде ранното оптимизиране било коренът на всички злини в програмирането...
Активен

A gentleman is one who is never rude unintentionally. - Noel Coward

gat3way

  • Напреднали
  • *****
  • Публикации: 6050
  • Relentless troll
    • Профил
    • WWW
Задача 2 - 10.09 - 16.09 - quotes web service
« Отговор #21 -: Sep 18, 2007, 19:18 »
Процесът да.

Нишката не.

Не че ми пука особено, щото не съм си играл да правя никакъв locking. Ама когато имаш няколко нишки дето барат обща заделена памет, общи файлови дескриптори и общи променливи, вероятностите за race conditions не са никак малки.

Процесите поне не си споделят толкова неща между родителя и "детето", там не се налага да мислиш особено за такива подробности.
Активен

"Knowledge is power" - France is Bacon

tarator

  • Напреднали
  • *****
  • Публикации: 849
    • Профил
Задача 2 - 10.09 - 16.09 - quotes web service
« Отговор #22 -: Sep 18, 2007, 19:21 »
Кой е казал, че нишките ще използват общи променливи? Всяка нишка си получава сокета, пуска fortune, праща и затваря...
Активен

A gentleman is one who is never rude unintentionally. - Noel Coward

gat3way

  • Напреднали
  • *****
  • Публикации: 6050
  • Relentless troll
    • Профил
    • WWW
Задача 2 - 10.09 - 16.09 - quotes web service
« Отговор #23 -: Sep 18, 2007, 19:30 »
...в това време нишката все някъде среща block-ваща функция и task scheduler-a пали некоя друга нишка. Все пак не мисля да пиша 100 отделни функции за 100 отделни нишки, които правят в общи линии едно и също, само че върху различен дескриптор. Вторият thread променя стойността на някакъв прост брояч и също заспива в един момент. Scheduler-a подкарва отново първата нишка, която пък точно се намирала в някакъв цикъл, зависещ от същият този, сега "променен" брояч. И да речем става някаква малка или голяма беля, в зависимост от случая.

Това е само един възможен сценарии и много зависи от дизайна, естествено. Ама многонишковото програмиране като цяло е една грозна каша и трябва да се мисли много внимателно в началото, защото после изникват разни такива странни моменти. Освен това много трудно се дебъгва, например strace отказва да ти следи кво ставало в рамките на някоя нишка.
Активен

"Knowledge is power" - France is Bacon

tarator

  • Напреднали
  • *****
  • Публикации: 849
    • Профил
Задача 2 - 10.09 - 16.09 - quotes web service
« Отговор #24 -: Sep 18, 2007, 19:41 »
> Все пак не мисля да пиша 100 отделни функции за 100 отделни нишки,
> които правят в общи линии едно и също, само че върху различен
> дескриптор.

А на мен ми се струва, че изобщо не мислиш. '<img'> Защо трябва да са отделни функциите след като локалните им променливи са в стека?

Многонишковото програмиране не е чак толкова трудно, изисква известна практика. Тренирайте, защото multicore процесорите няма да изчезнат и единствения начин за ефективното им използване ще е многонишковото прогрмиране '<img'>
Активен

A gentleman is one who is never rude unintentionally. - Noel Coward

gat3way

  • Напреднали
  • *****
  • Публикации: 6050
  • Relentless troll
    • Профил
    • WWW
Задача 2 - 10.09 - 16.09 - quotes web service
« Отговор #25 -: Sep 18, 2007, 20:08 »
Имам предвид ако имаш някаква структура описваща всички конекции, състоянието им и т.н. Няма как да ти е локална променлива все пак '<img'> И например единия клиент затвори конекцията, ще се наложи нишката да го отрази по някакъв начин.

Уфф абе добре, ясно, пак опираме до дизайна на нещата очевидно '<img'> И в тоя случай специално може да се измисли наистина '<img'> От друга страна, този случай специално е доста прост '<img'> В един по-забавен вариант, отделните клиенти трябва да си обменят някакви данни, например става въпрос за някакъв елементарен чат сървър, тогава вече няма да има измъкване от тая проблематика, поне аз сега не мога да измисля '<img'>
Активен

"Knowledge is power" - France is Bacon

tarator

  • Напреднали
  • *****
  • Публикации: 849
    • Профил
Задача 2 - 10.09 - 16.09 - quotes web service
« Отговор #26 -: Sep 18, 2007, 20:15 »
> Имам предвид ако имаш някаква структура описваща всички конекции,
> състоянието им и т.н.

За какво ти е такава структура'<img'> Основната нишка прави

fd = accept();
pthread_create(x, NULL, process_connection, fd);

process_creation чете и пише от fd-то и накрая го затваря.

Проблемът е от т.нар. embarrassingly parallel, няма нужда от никакви заключвания или комуникации между нишките.

Отделно не виждам никакъв смисъл програмите сами да се занимават със сокети след като могат да използват inetd за целта. KISS!
Активен

A gentleman is one who is never rude unintentionally. - Noel Coward

gat3way

  • Напреднали
  • *****
  • Публикации: 6050
  • Relentless troll
    • Профил
    • WWW
Задача 2 - 10.09 - 16.09 - quotes web service
« Отговор #27 -: Sep 18, 2007, 20:18 »
Шшшшш xinetd '<img'> RHEL не ползваш ли? '<img'>
Активен

"Knowledge is power" - France is Bacon

tarator

  • Напреднали
  • *****
  • Публикации: 849
    • Профил
Задача 2 - 10.09 - 16.09 - quotes web service
« Отговор #28 -: Sep 18, 2007, 20:25 »
x, y, z, inetd си е inetd, от програмистка гледна точка няма разлика, за другото да му мислят сисадмините.
Активен

A gentleman is one who is never rude unintentionally. - Noel Coward

gat3way

  • Напреднали
  • *****
  • Публикации: 6050
  • Relentless troll
    • Профил
    • WWW
Задача 2 - 10.09 - 16.09 - quotes web service
« Отговор #29 -: Sep 18, 2007, 20:29 »
Ееееем...аз не съм програмист. inetd е много лоша идея между другото ако става въпрос за каквото и да било UDP-базирано '<img'>

Между другото, от администраторска гледна хич не е едно и също '<img'>



Активен

"Knowledge is power" - France is Bacon

Подобни теми
Заглавие Започната от Отговора Прегледи Последна публикация
Kak da napravq skript service?
Настройка на програми
karolev 1 9922 Последна публикация Nov 27, 2002, 14:17
от brady
Проблем със Qmail service
Настройка на програми
Shoty 9 11251 Последна публикация Oct 21, 2005, 12:23
от PlamenB
PPPoE Service Name в UBUNTU
Настройка на програми
moosehead 0 6009 Последна публикация Feb 22, 2006, 02:16
от moosehead
Customer service representative with French
Търсене
AdeccoBulgaria 0 5299 Последна публикация Sep 29, 2009, 16:51
от AdeccoBulgaria
minimal service on startup
Настройка на програми
vox 11 11514 Последна публикация Sep 12, 2011, 10:20
от plamen_f