Tuesday, December 1, 2009

SW302 - Лабораторын ажил 9

Энэ лабораторын ажлаар энгийн вэб сервэр програм бичиж турших болно. Сокет програмчлалыг судлах зорилгоор энгийн вэб сервэр програм ямархуу байж болохыг харцгаая. Эхлээд вэб сервэр програм гэж юу вэ гэдгийг жаахан тодорхой болгоё.
  • Вэб сервэр програм нь сүлжээгээр дамжуулан хэрэглэгч буюу үйлчлүүлэгч програмуудад (Mozilla Firefox, Internet Explorer, Safari, ...) үйлчилдэг. Бид өөрсдийн компьютер дээрээ үйлчлүүлэгч програмаа ажиллуулж ямар нэгэн хаяг болон порт (http://www.csms.edu.mn:8080/) зааж өгдөг. Хэрэв порт зааж өгөөгүй бол 80 -р порт гэж тооцдог. Үйлчлүүлэгч програм бидний зааж өгсөн тэр хаяг руу хандахад тэр машин дээр ажиллаж байгаа сервэр програм хүсэлтийг хүлээж аваад тохирох хариуг илгээнэ.
  • Үйлчлэгч болон үйлчлүүлэгч програмууд хоорондоо ойлголцохын тулд стандарт нэг зөвшилцөл буюу протокол ашигладаг. Энэ протокол нь HTTP буюу Hyper Text Transfer Procotol юм. Hyper Text -г вэбээр бидний үзэж байгаа мэдээлэл гэж ойлгож болно. Тэгэхээр энэ нь текст мэдээллийг сервэр ба клиентийн хооронд дамжуулахад баримталдаг дүрэм буюу тэдгээрийн хоорондоо ойлголцдог хэл нь байх нь.
  • HTTP-р текст мэдээлэл дамжуулахаас гадна зураг, дуу гэх мэт дурын файл дамжуулж болно.
  • Харин текстийн өнгө, хэлбэр, хэмжээ, хүснэгтэн мэдээлэл гэх мэтийг тусгай хэлээр хэвжүүлж илгээдэг. Энэ хэл нь мэдээж HTML буюу Hyper Text Markup Language юм.

Тэгэхээр вэб сервэр програм бичиж байгаа хүн энэ 2 -г (HTTP, HTML) тодорхой түвшинд мэддэг байх хэрэгтэй. Доорх хаягаас мэдээлэл авч болно.

http://www.jmarshall.com/easy/http/
http://www.cs.virginia.edu/~zaher/classes/CS851/Web_lecture/tsld001.htm

Бидний бичих вэб сервэр нь тухайн агшинд системд нэвтэрсэн байгаа хэрэглэгчдийн мэдээллийг (who командын үр дүн) буцаадаг байх юм. Энэ мэдээлэл нь вэб зууч програм дээр хүснэгт байдлаар харагдах ёстой. (Маш энгийн) Жишээ нь:

Хэрэглэгчийн нэр Нэвтэрсэн арга Хугацаа Хаанаас
hasherdene pts/6 2008-12-03 16:16 (202.131.233.98)
sw00d089   pts/4 2008-12-03 15:10 (210.137.174.225)

Ажиллах дараалал
0. Өөрийнхөө pid-г хэвлэнэ.
1. Интернэтийн сокет үүсгээд, зааж өгсөн портыг bind хийнэ. (Жишээ нь: ./lab9 --port=10001)
2. Хүсэлт хүлээн сонсоно.
3. Үйлчлүүлэгч холбогдмогц өөрийгөө fork хийгээд эцэг нь 2-р алхам руу шилжинэ. Хүү нь шаардлагатай мэдээллийг буцаагаад өөрөө дуусна.
4. Эцгийг kill командаар устгана.

Даалгавар

Доорх програмыг хөрвүүлж ажиллуулж эх код болон ажиллах програмыг ~sw302/lab09 дотор байрлуул. Шаардлагатай мөрөнд тайлбар бичнэ.


#include <stdio.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <string.h>
#include <bits/socket.h>
#include <regex.h>


#define handle_error(msg) do { perror(msg); exit(EXIT_FAILURE);} while(0);


void err_arg(char*);
void serve_client(int, struct sockaddr_in *, int);


int
main(int argc, char **argv){
    if(argc <= 1) err_arg(argv[0]);
    int port;
    if(sscanf(argv[1], "--port=%d", &port) != 1) err_arg(argv[0]);
   
    int sd;
   
    if((sd = socket(AF_INET, SOCK_STREAM, 0)) == -1) handle_error("socket");
    struct sockaddr_in address;
    memset(&address, 0, sizeof(struct sockaddr_in));
    address.sin_family = AF_INET;
    address.sin_port = htons((short)port);
    address.sin_addr.s_addr = 0;
    /* Doorhi murund tailbar heregtei */   
    if( bind(sd,(struct sockaddr*) &address, sizeof(address)) == -1) handle_error("bind");
    if( listen(sd, 16) == -1) handle_error("listen");
    while(1){
        struct sockaddr_in client_address;
        int client_addr_size = sizeof(client_address);
        /* Doorhi murund tailbar heregtei */
        int c_sd = accept(sd, (struct sockaddr*)&client_address, &client_addr_size);
        printf("Client connected: sd = %d\n", c_sd);
        fflush(stdout);
        /* Doorhi murund tailbar heregtei */
        int c_pid = fork();
        if ( c_pid < 0) handle_error("fork");
        if ( c_pid == 0 ){
            /* Doorhi murund tailbar heregtei */
            serve_client(c_sd, &client_address, client_addr_size);
            shutdown(c_sd, SHUT_RDWR);
            close(c_sd);
            exit(EXIT_SUCCESS);
        }
    }
    close(sd);
   
    return 0;
}


void
err_arg(char *argv){
    printf("Usage:\n%s --port=PORT\n", argv);
    exit(EXIT_FAILURE);
}


char *
make_row(char *line){
    regex_t reg;
    int j;
#define SIZE_MATCH 6
    regmatch_t pmatch[SIZE_MATCH];
    if( regcomp(&reg, "^([^ ]*) *([^ ]*) *([^ ]* [^ ]*) *([^ ]*)$", REG_EXTENDED) != 0 ) handle_error("regcomp");
    if( regexec(&reg, line, SIZE_MATCH, pmatch, 0) != 0 ) handle_error("regexec");
    line[pmatch[1].rm_eo] = '\0';
    line[pmatch[2].rm_eo] = '\0';
    line[pmatch[3].rm_eo] = '\0';
    line[pmatch[4].rm_eo] = '\0';
    char *table_row = malloc(1000);
    regfree(&reg);
    sprintf(table_row, "%s%s%s%s",
        line + pmatch[1].rm_so, line + pmatch[2].rm_so, line + pmatch[3].rm_so, line + pmatch[4].rm_so);
    return table_row;
}


void
serve_client(int c_sd, struct sockaddr_in * client_address, int client_addr_size){
    /*nevtersen hereglegchdiin medeelliig avahiin tuld getutent() -g ashiglaj
    boloh bolovch popen()-g turshih uudnees who komandiig ashiglasan*/

    FILE *pipe = popen("who", "r");
    char *line = NULL;
    size_t len = 0;
    if (pipe == NULL) handle_error("popen");
    char *response_lines[1000];
    int current_line = 0;
   
    char header_template[] =    "HTTP/1.0 200 OK\n"
                    "Server: Sw302Lab9/0.1\n"
                    "Content-Type: text/html\n"
                    "Content-Length: %d\n"
                    "Last-Modified: Wed, 03 Dec 2008 16:28:07 GMT\n"
                    "Date: Wed, 03 Dec 2008 16:28:07 GMT\n\n";
    char response_header[500] = {0};
    response_lines[ current_line ++ ] = response_header;
    char html_body_h[] = "<body><table cellspacing=\"1\" cellpadding=\"1\" border=\"1\">";
    response_lines[ current_line ++ ] = html_body_h;
    char html_table_title[] =   "<tr>"
                    "<td style=\"text-align: center;\"><strong>Хэрэглэгчийн нэр
                    "<td style=\"text-align: center;\"><strong>Нэвтэрсэн арга</strong></td>"
                    "<td style=\"text-align: center;\"><strong>Хугацаа</strong></td>"
                    "<td style=\"text-align: center;\"><strong>Хаанаас</strong></td>"
                    "</tr>";
    response_lines[ current_line ++ ] = html_table_title;
    while (getline(&line, &len, pipe) != -1) {
        char *table_row = make_row(line);
        response_lines[ current_line ++ ] = table_row;
    }
    if (line) free(line);
    char html_footer[] = "</table></body>";
    response_lines[ current_line ++ ]  = html_footer;
    int i, content_size = 0;
    for(i = 1; i < current_line; i++){
    /* Doorhi murund tailbar heregtei */
        content_size += strlen(response_lines[i]);
    }
    /* Doorhi murund tailbar heregtei */
    sprintf(response_header, header_template, content_size);
    for(i = 0; i < current_line; i++){
    /* Doorhi murund tailbar heregtei */
        write(c_sd, response_lines[i], strlen(response_lines[i]));
    }
        for(i = 3; i < current_line-1; i++){
    /* Doorhi murund tailbar heregtei */
        free(response_lines[i]);
        }
}

No comments:

Post a Comment