Задача: Реализация Модельного веб-сервер

Тема в разделе "C/C++/C#", создана пользователем BashOrgRu, 18 ноя 2010.

  1. BashOrgRu

    BashOrgRu Well-Known Member

    Регистрация:
    15 мар 2009
    Сообщения:
    78
    Симпатии:
    0
    Дали задание, написать модельный веб-сервер без CGI: "Сайты, в которых информация (ресурсы) представляет собой набор файлов (обычно – в формате HTML – т.н. веб-страницы), называются статическими. ". То есть нужно сделать реализация модельного веб-сервера, поддерживающуго описанное ниже подмножество протокола HTTP.
    HTTP-запрос
    HTTP-запрос отправляется веб-клиентом к веб-серверу и имеет вид:
    <заголовок запроса> <конец строки>
    <HTTP- заголовок > <конец строки>

    <HTTP- заголовок > <конец строки>
    < конец строки >
    <тело запроса>

    Здесь и далее <конец строки> - это символ с кодом 10 (\n).
    Структура заголовка запроса имеет вид:
    < HTTP -метод> URI HTTP/<версия протокола>

    Метод GET
    Этот метод используется для запроса содержимого ресурса с
    сервера. Файл ресурса определяется URI из запроса. Если URI корректен,
    то сервер обязан вернуть содержимое запрашиваемого файла, если это
    файл данных.
    Примеры заголовков запроса GET:
    GET /index.html HTTP/1.1
    По этому запросу сервер возвращает текст файла index.html из
    домашней директории сервера.

    Метод HEAD

    HTTP-ответ
    Ответ веб-сервера имеет следующую структуру:
    <заголовок ответа> <конец строки>
    <HTTP- заголовок > <конец строки>

    <HTTP- заголовок > <конец строки>
    < конец строки >
    <тело ответа>

    Заголовок ответа выглядит так:
    HTTP/<версия протокола> <код состояния> <пояснение>


    Заголовок Date

    Заголовок Host

    Заголовок Referer

    Заголовок User-agent

    Заголовок Server

    Заголовок Content-length

    Заголовок Content-type

    Заголовок Allow

    Заголовок Last-modified

    "Рекомендуется начать реализацию с двух простых программ, которые пригодятся при тестировании. Первая программа – «псевдо-сервер», цель которого – запись реальных запросов, посылаемых веб-клиентами например, различными веб-браузерами). Такой сервер должен принять запрос, записать его в лог-файл, выдать ответ с кодом 501 «Not Implemented» и немедленно закрыть соединение. Ответ можно заготовить заранее как текстовый файл и выдавать его в сокет по мере надобности. Сохраненные запросы можно использовать для отладки сервера. Для того, чтобы посылать эти запросы к серверу, понадобится еще одно простое приложение – «псевдо-браузер». Это консольное приложение, которое устанавливает связь с сервером, посылает ему заранее заготовленный запрос (тут-то пригодится «псевдо-сервер», хотя тестовые запросы можно приготовить и «вручную») и записывает ответ сервера."


    Прошу помочь хоть какой-нибудь информацией по поводу этого или примеров программ. От нас требуют, чтобы мы уже сдавали этот модельный веб-сервер, хотя ни на лекциях, ни на семинарах мы ещё не дошли до сокетов.
    На всякий случай, если я непонятно описал задачу, то присоединяю файл, в котором описано подробно задание, и из этого задания мне надо сделать первый этап.
    Заранее блогадарен.
     

    Вложения:

    • httpserver.pdf
      Размер файла:
      288,7 КБ
      Просмотров:
      13
  2. lazybiz

    lazybiz Well-Known Member
    C\C++ Team

    Регистрация:
    3 ноя 2010
    Сообщения:
    1.344
    Симпатии:
    0
    Код (C++):
    // обычная подготовка TCP/IP сервера
    int serverSocket = socket (AF_INET, SOCK_STREAM, 0);
    ...
    struct sockaddr_in ServerAddress;
    // заполнить ServerAddress
    // ...
    if (bind(serverSocket, &ServerAddress, sizeof(ServerAddress)) < 0)
    ... // фатальная ошибка
    if (listen(serverSocket, BACK_LOG) < 0)
    ... // фатальная ошибка

    // главный цикл
    for (;;) {
    struct sockaddr_in ClientAddress;
    size_t ClAddrLen = sizeof(ClientAddress);

    // ждем очередного клиента
    int clSocket = accept((serverSocket, &ClientAddress, &ClAddrLen);
    if (clSocket < 0) ... // ошибка - если будет повторяться, то фатальная
    // собственно обработка запроса. Должна включать в себя корректный разрыв связи (shutdown - close)
    ProcessClientRequest(clSocket, &ClientAddress);
    }
    Ты не поверишь где я это нашел..
     
  3. BashOrgRu

    BashOrgRu Well-Known Member

    Регистрация:
    15 мар 2009
    Сообщения:
    78
    Симпатии:
    0
    ну это да) Мне примеры того что должно быть на входе и на выходе у сервера, то есть ему как я понимаю подают на ввод команду либо GET либо HEAD, а в ответ что-то получают. Так вот нужен пример того что на ввод и что на вывод должен делать сервер, а не абстрактное объяснения, как в том файле. И ещё, как я понял, сервер должен работать со статическими веб-сайтами, то есть в папке с сервером должны лежать файлы типа html и он по запросам клиента должен их отправлять? Или как?
     
  4. DarkKnight

    DarkKnight Well-Known Member
    C\C++ Team

    Регистрация:
    1 авг 2010
    Сообщения:
    653
    Симпатии:
    0
    А уже есть свои наработки какие-нибудь???
    И вообще вам сам принцип работы веб-сервера понятен???
    Может быть когда-нибудь сталкивались с рабочим каким-нибудь (например с Apachем) ?
    P.S. Это что бы точно знать с чего начать вам помогать :)
     
  5. BashOrgRu

    BashOrgRu Well-Known Member

    Регистрация:
    15 мар 2009
    Сообщения:
    78
    Симпатии:
    0
    Наработок нет, так как не понятно, что нужно делать. Почитав разные мануалы, только примерно понимаю приницип работы веб-сервера. Не, не сталкивался)

    Добавлено: Как бы работу с сокетами частично понимаю, но вот что должен получить и отправлять не могу никак понять)
     
  6. DarkKnight

    DarkKnight Well-Known Member
    C\C++ Team

    Регистрация:
    1 авг 2010
    Сообщения:
    653
    Симпатии:
    0
    Щас у меня пол первого утра, так что сил что то писать нету :))) Я завтра тебе помогу... И досканально попробую объяснить.....
    Вообщем за выходные что-нить общими усилями родим ;-)
     
  7. BashOrgRu

    BashOrgRu Well-Known Member

    Регистрация:
    15 мар 2009
    Сообщения:
    78
    Симпатии:
    0
    Спасибо огромное! Мне вприницпе просто надо досконально объянсить что должен делать сервер) Первым заданием семестра - написанием шела для Unix, справился легко, так как знал, что там вобще от меня требуются, а тут вобще тьма...
     
  8. DarkKnight

    DarkKnight Well-Known Member
    C\C++ Team

    Регистрация:
    1 авг 2010
    Сообщения:
    653
    Симпатии:
    0
    Вот... Для начала примерно так это должно выглядить....

    Код (C++):
    #include <iostream>
    #include <WinSock.h> //Заголовочный файл сокетов

    #pragma comment(lib,"wsock32.lib") //Подключим библиотеку

    using namespace std;

    char buffer[] = "HTTP/1.1 200 Ok\nContent-Type: text/html\n\n<HTML><HEAD><TITLE>ModalServer 1.1b</TITLE></HEAD>\n<BODY bgcolor='green' text='yellow'>\n<H1>Я пока еще не умею обрабатывать запросы</H1>\n</HTML>";

    int main (void)
    {

    setlocale(LC_ALL,"Russian"); //Установим локаль
    WSADATA wsaData; //WSA заглушка
    WORD WINSOCK_VERSION = MAKEWORD(2,2); //Версия сокетов

    cout<< "....Загрузка WebServerа...."<< endl;
    Sleep(1000); //Сделаем паузу так будет красивее

    //Инициализация WSA
    if (!WSAStartup(WINSOCK_VERSION,&wsaData))
    cout<< "Инициализация WSA выполнена успешно"<< endl;
    else{
    cout<< "Error: Ошибка инициализации WSA"<< endl;
    return -1;
    }

    int ServerSocket = socket (AF_INET, SOCK_STREAM, 0); //Наш сокет
    struct sockaddr_in ServerAddress; //Структура sockaddr_in
    ServerAddress.sin_addr.s_addr = INADDR_ANY;
    ServerAddress.sin_port = htons(8888); //Будем отслеживать порт 8888
    ServerAddress.sin_family = AF_INET;

    if (bind(ServerSocket,(LPSOCKADDR)&ServerAddress, sizeof(ServerAddress))== SOCKET_ERROR)
    {
    cout<< "Не могу забиндить \n";
    } else cout<< "Bind is OK"<< endl;

    if (listen(ServerSocket,3) != SOCKET_ERROR)
    {
    cout<< "Прослушивание выполнено " << endl;
    }
    struct sockaddr_in clAddr;

    int clAddrLen = sizeof(clAddr);
    while (1)
    {
    int clSocet = accept(ServerSocket,(LPSOCKADDR)&clAddr,&clAddrLen);
    char *Rv = new char[1024];
    memset(Rv,0,1024);
    recv(clSocet,Rv,1024,0);
    cout<< "Запрос к серверу :"<< endl;
    cout<< Rv<< endl;
    cout<< "------------------------------------------------------------"<< endl;
    send(clSocet,buffer,sizeof(buffer),0);
    cout<< "Ответ послан"<< endl;

    shutdown(clSocet,0);
    closesocket(clSocet);

    }
    //Завершим WSA
    WSACleanup();


    }
     

    Вложения:

    • websrv1.jpg
      websrv1.jpg
      Размер файла:
      65,1 КБ
      Просмотров:
      136
    • websrv2.jpg
      websrv2.jpg
      Размер файла:
      118,7 КБ
      Просмотров:
      137
  9. BashOrgRu

    BashOrgRu Well-Known Member

    Регистрация:
    15 мар 2009
    Сообщения:
    78
    Симпатии:
    0
    DarkKnight125, спасибо, теперь уже более менее ясно. Только тот код, что ты написал, сделан на C++(который пока не знаю), а мне надо на С сделать, так что какие команды из твоего кода не доступны в C?)
     
  10. DarkKnight

    DarkKnight Well-Known Member
    C\C++ Team

    Регистрация:
    1 авг 2010
    Сообщения:
    653
    Симпатии:
    0
    А вы на чем именно пишите????
    Вернее чем компилируете?
     
  11. BashOrgRu

    BashOrgRu Well-Known Member

    Регистрация:
    15 мар 2009
    Сообщения:
    78
    Симпатии:
    0
    GCC в Unix'е
    я так подозреваю, что кроме команд типа " cout<< "Запрос к серверу :"<< endl;" все остальные команды есть в С?
     
  12. DarkKnight

    DarkKnight Well-Known Member
    C\C++ Team

    Регистрация:
    1 авг 2010
    Сообщения:
    653
    Симпатии:
    0
    Код (C++):
    using namespace std;
    еще ;-) Все остальное есть...
    Я допишу когда напишу как для *nixов переложить код, там несколько разногласий с виндой, небольших, таких например как
    определение заголовочных файлов:
    Код (C++):
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    Вот этой "срани" нету, она там просто не нужна ;-))
    Код (C++):
    closesocket(clSocet);
    //Он будет вызываться просто
    close(clSocet)
    Ну вроде и все....

    А пока cin и cout смело заменяй на
    printf и scanf
     
  13. BashOrgRu

    BashOrgRu Well-Known Member

    Регистрация:
    15 мар 2009
    Сообщения:
    78
    Симпатии:
    0
    :) спасибо)
    А вот в ответ сервер должен на запрос, например, "GET /topic39269.html"(что-то типо такого) посылать код странички? Или например на метод head. Вобщем, как должен выглядить наш ответ? Можно не готовый код, а просто хотя бы пример нескольких команд в сервер и от сервера, естественно, без CGI.
     
  14. BashOrgRu

    BashOrgRu Well-Known Member

    Регистрация:
    15 мар 2009
    Сообщения:
    78
    Симпатии:
    0
    А ip: 192.168.1.2 , по которому находится сервер, где указывал в коде?
     
  15. DarkKnight

    DarkKnight Well-Known Member
    C\C++ Team

    Регистрация:
    1 авг 2010
    Сообщения:
    653
    Симпатии:
    0
    Это мой локальный Ip ;-)) Можно заместо него узать 127.0.0.* любой....
    Его не надо указывать, отлавливаются все сокеты TCP/IP которые прилетают на 8888 порт ;-)))

    З.Ы. С ответом я завтра допишу... И асинхронную обработку тоже завтра сделаю.... :) Яж написал это только начало, но в тоже время это и основная часть ;-)

    Ну а если побаловаться хочешь, то делай так... Получаешь имя файла(вытаскиваешь его с запроса) GET /index.html...
    Вытащил имя /index.html
    Открываешь его для чтения, читаешь, и отправляешь шапку(которую я написал в буфер, кроме текста)+ весь файл...
    И вот у тебя уже в браузере требуемая страница
     
  16. BashOrgRu

    BashOrgRu Well-Known Member

    Регистрация:
    15 мар 2009
    Сообщения:
    78
    Симпатии:
    0
    Вот слегка доделал, теперь файлы выдаёт. Но когда надо запрашывает файл расширения png или gif, то выходит ошибка чтения, как я понимаю, это fgetc, надо заменить на fread, но fread почему-то не пашет)
    Теперь вопросы:
    text/plain - в какой случае Content-Type такой должен быть?
    Есть ли какой-то способ на C посылать серверу ответы типа "HTTP/1.(какое-то число) (какое-то число) (какое-то слово)\nContent-Type: (какое-то слово)"?
    Где можно метод HEAD отловить из запроса браузера?))

    Код (Text):
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <sys/un.h>
    #include <netinet/in.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <locale.h>

    struct word{
    char *cont;
    struct word *next;
    };

    char buffer[] = "HTTP/1.1 200 Ok\nContent-Type: text/html";

    struct word *CreatList(char *str, int Count){
    int i=0,is=-1,j,mark=0,k,p;
    struct word *head,*Elem;

    head=(struct word *)malloc(sizeof(struct word));
    Elem=head;
    while(i!=(Count+1)){
    if ( str[i]==' ' || str[i]=='\n' || i==Count ){
    Elem->cont=malloc((i-is)*sizeof(char));
    k=0;
    for (j=(is+1);j<i;j++){
    *((Elem->cont)+k)=str[j];
    k++;
    }
    *((Elem->cont)+k)='\0';
    if (i!=Count)
    Elem->next=(struct word *)malloc(sizeof(struct word));
    else
    Elem->next=NULL;
    Elem=Elem->next;
    is=i;
    }
    i++;
    }
    return (head);
    }

    char *OpRF(char *name){
    char c;
    FILE *fp;
    int i=0;
    for (i=0;i<strlen(name);i++) name[i]=name[i+1];
    if (name[0]=='\0') name="index.htm\0";
    if ((fp=fopen(name,"r"))==NULL){
    printf("Ошибка чтения\n");
    return NULL;
    }
    fseek(fp,0,SEEK_END);
    int l;
    l=ftell(fp);
    char *str=malloc((l+1)*sizeof(char));
    i=0;
    close(fp);
    fp=fopen(name,"r");
    while((c=fgetc(fp))!=EOF){
    str[i]=c;
    i++;
    }
    str[i]='\0';
    close(fp);
    return str;
    }

    int main (void)
    {
    struct word *Sp;
    char *str;
    int i=0,ServerSocket = socket (AF_INET, SOCK_STREAM, 0);
    struct sockaddr_in ServerAddress;

    ServerAddress.sin_addr.s_addr = INADDR_ANY;
    ServerAddress.sin_port = htons(8888);
    ServerAddress.sin_family = AF_INET;

    if (bind(ServerSocket,(struct sockaddr *)&ServerAddress, sizeof(ServerAddress))<0)
    {
    printf( "Не могу забиндить \n");
    return 0;
    } else printf( "Bind is OK\n");

    if (listen(ServerSocket,3) >=0)
    printf("Прослушивание выполнено \n");
    else return 0;
    struct sockaddr_in clAddr;

    int clAddrLen = sizeof(clAddr);
    while (1)
    {
    int clSocet = accept(ServerSocket,(struct sockaddr *)&clAddr,&clAddrLen);
    char Rv[1024];
    memset(Rv,0,1024);
    recv(clSocet,Rv,1024,0);
    printf( "Запрос к серверу :\n");
    printf("%s",Rv);
    Sp=CreatList(Rv,strlen(Rv));
    str=OpRF((Sp->next)->cont);
    printf( "------------------------------------------------------------\n");
    send(clSocet,buffer,sizeof(buffer),0);
    if (str!=NULL)
    send(clSocet,str,strlen(str),0);
    printf("Ответ послан\n");
    shutdown(clSocet,0);
    close(clSocet);
    }
    return 0;
    }
     
  17. DarkKnight

    DarkKnight Well-Known Member
    C\C++ Team

    Регистрация:
    1 авг 2010
    Сообщения:
    653
    Симпатии:
    0
    Код (Text):
    HTTP/1.1 200 Ok
    MIME-version: 1.1
    Content-Type: image/gif (Ну смотря какой формат)
    Content-Length: [в этом месте размер катинки в байта]
    \n
    [бинарный вывод файла]
    Код (Text):
    Если картинка не найден то просто высылай
    HTTP/1.1 404 File Not Found
    ]\n
    Еще раз повторюсь что файл должен быть открыт для бинарного чтения
    fp=fopen(name,"r+b");
     
  18. BashOrgRu

    BashOrgRu Well-Known Member

    Регистрация:
    15 мар 2009
    Сообщения:
    78
    Симпатии:
    0
    Спасибо)
     
  19. BashOrgRu

    BashOrgRu Well-Known Member

    Регистрация:
    15 мар 2009
    Сообщения:
    78
    Симпатии:
    0
    Поле Last-modified, со статичиским ресурсом должно содержать время первого запроса к этому ресурсу?
     
  20. DarkKnight

    DarkKnight Well-Known Member
    C\C++ Team

    Регистрация:
    1 авг 2010
    Сообщения:
    653
    Симпатии:
    0
    Неа... Время изменения запрашиваемого файла...
    Смысл же в том, что бы из кэша подтянуть если он не изменился....
     
Загрузка...
Похожие Темы - Задача Реализация Модельного
  1. Янчик
    Ответов:
    0
    Просмотров:
    481
  2. TrishaRay
    Ответов:
    1
    Просмотров:
    781
  3. elzim
    Ответов:
    0
    Просмотров:
    929
  4. ShaoKahn
    Ответов:
    0
    Просмотров:
    1.117
  5. eremin-sanek
    Ответов:
    3
    Просмотров:
    1.105

Поделиться этой страницей