Здравствуйте, Handler, Вы писали:
H>Теперь встал еще один вопрос: Как отправить заголовок браузеру? Т.е.: H>в php ч/з header(), а в с++ — ? H>Начнем с самого простого, без чего, якобы, браузер вообще не сможет прочитать содержимое ответа (но, тем не менее, читает) — Content-length:
Без Content-Length и браузер, и сервер, считают закрытие соединения признаком конца сообщения.
Хотя так делать крайне не рекомендуется.
H>
H>string str = "<html>...</html>";
H>string reply = "Content-length: "+str.length();
H>reply+= "\r\n\r\n"; // end of header
H>reply+= str;
H>
А где статусная строка (HTTP/1.1 200 OK) ?
H>Здесь все отлично — браузер отображает содержимое документа, причем сам заголовок в теле документа не отображается. H>Далее хочу отправить кодировку в документ, т.к. документ у меня в cp-1251, а браузер — в utf-8 (default): H>Какой же параметр устанавливает кодировку в заголовке?
Клиент говорит серверу о том, в какой кодировке он желает получить ответ, с помощью Accept-Charset.
Сервер обозначает кодировку ответа внутри Content-Type. Например: "Content-Type: text/html; charset=utf-8".
Если кодировка не указывается, для HTML по умолчанию берется ISO-8859-1, а для XHTML — UTF-8.
H>Ни один из этих вариантов браузер не считает за заголовки и выводит их в основное тело документа. H>Как правильно и какие заголовки посылать браузеру?
Это потому, что Вы не читаете спецификацию, и, подозреваю, даже не заглядываете в предыдущие ответы темы.
А HTTP, между тем, не такой уж и примитивный протокол, и в нем не все лежит на поверхности.
Книги:
HTTP Developer's Handbook (C. Shiflett)
HTTP: The Definitive Guide (D. Gourley, B. Totty, M. Sayer, S. Reddy, A. Aggarwal)
Web-протоколы: теория и практика НТТР/1.1, взаимодействие протоколов, кэширование, измерение трафика
(Б. Кришнамурти, Дж. Рексфорд)
0) болт кладем на вух ораторов выше( пока руками не научитесь пользоваться — обертки будут лишь дурманющим разум зельмем ).
1) в гугле вбиваем "пример TCP сервер linux".
2) прогоняем через ман каждую функцию.
В качестве подсказки:
{
int server_sock = socket( ... ); // собственно создаем дескриптор серверного сокета.
...
bind( ... ); // связываем определенный адрес с сокетом - в примере это 0.0.0.0:8080.
...
listen( ... ); // врубаем механизм.
...
// Теперь нужно принять подключение:int client_sock = accept( ... );
// ^^^^^^
// вот это клиентский сокет. для чтения и писанины скрещивать его с функциями read/write.
...
close( client_sock ); // все в имени моем.
...
close( server_sock ); // ----- // -----
}
Здравствуйте!
Задача:
Создать приложение демон-процесс, слушающий и обрабатывающий запросы к TCP порту основанные на HTTP, выдающий в результате обработки запроса HTML-контент взятый из базы данных mysql, выполняющий перекодирование выдаваемого контента в желаемую/затребованную кодировку, которая устанавливается либо в самом запросе, либо в настройках его инициализационных параметров.
К сожалению, никогда не писал С++ программ для работы в сети, поэтому не представляю себе, что и в какой последовательности работает.
Я написал следующую программу:
int main (int argc, char * const argv[]) {
struct sockaddr_in addr_info;
int add_len = sizeof(addr_info);
int ret_addr, sock_id;
char* buf = new char[256];
Но я так понимаю, что это совсем не в ту сторону. Единственное, что тут правильно — это socket().
Пожалуйста, подскажите схему приложения-реализации данной задачи, что за чем следует, а я постараюсь по Вашей схеме написать реализацию.
Заранее благодарен.
Алексей
28.09.11 13:56: Перенесено модератором из 'C/C++' — Odi$$ey
Whoa...I did a 'zcat /vmlinuz > /dev/audio' and I think I heard God...
Здравствуйте, Handler, Вы писали:
H>К сожалению, никогда не писал С++ программ
в вашем коде, из с++, только new и cout. так что программа написана на Си.
смотрите boost.asio.
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Возьмите книжку Стивенса по сетевым приложениям.
Прочитайте оттуда буквально три первые главы (100 стр.) — и все вопросы отпадут.
PS: boost.asio смотреть рано.
Меня смущает тот факт, что все примеры, которые я встречал, описывают клиент-серверную модель, а мне, скорее всего нужна модель типа tcpdump.
Спасибо, что дали направление
Whoa...I did a 'zcat /vmlinuz > /dev/audio' and I think I heard God...
Здравствуйте, pavard, Вы писали: P>0) болт кладем на вух ораторов выше( пока руками не научитесь пользоваться — обертки будут лишь дурманющим разум зельмем ).
ох уж эти велокодеры.. они такие забавные 8)
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Нет такой модели tcpdump. Отдавать контент по хттп — дело сервера, запрашивать этот контент — дело клиента. Отсюда и название клиент-серверное.
Название tcpdump = tcp + dump = сдампь чтоб я посмотрел что там бегает = тупо утилита чтоб посмотреть.
В общем, проще будет пойти от главного — разобраться в целях. И зрите не в список целей написать то-то то-то, а в список — я не понимаю того-то того-то.
Здравствуйте, Handler, Вы писали:
H>Задача: H>Создать приложение демон-процесс, слушающий и обрабатывающий запросы к TCP порту основанные на HTTP, выдающий в результате обработки запроса HTML-контент взятый из базы данных mysql, выполняющий перекодирование выдаваемого контента в желаемую/затребованную кодировку, которая устанавливается либо в самом запросе, либо в настройках его инициализационных параметров. H>К сожалению, никогда не писал С++ программ для работы в сети, поэтому не представляю себе, что и в какой последовательности работает. H>Пожалуйста, подскажите схему приложения-реализации данной задачи, что за чем следует, а я постараюсь по Вашей схеме написать реализацию.
Слишком крутой заложен вираж.
Если сетевые приложения до этого никогда не писались, то сразу реализовать такой конвейер, — а тут и
работа с TCP, и обработка HTTP, и работа с кодировками, и база данных, — будет непросто.
В целях обучения лучше разбить эту задачу на составляющие и попытаться освоить их изолированно друг от друга.
Для начала разобраться с TCP/IP, научиться писать простые клиент-серверы и передавать сообщения, а
также корректно размыкать соединения. По TCP есть несколько неплохих книжек.
Потом понять, какие места занимают TCP и HTTP в стеке OSI.
HTTP тоже крепкий орешек, лучше всего скачать последние RFC (1.0/1.1) и вызубрить их от корки до корки, а
еще найти хорошую книгу по этому протоколу. Потом уже можно пытаться писать свой HTTP-сервер и стучаться к
нему из браузера. Отдельное место в этом всем занимает вопрос производительности и масштабируемости.
По ходу изучения будут возникать всякие нюансы и тонкости, которые и сформируют определенные знания о
том, как на самом деле работают веб-клиенты и веб-серверы. А тонкостей будет много.
Ну и только после этого можно садиться и писать веб-приложения.
P.S.
Простой HTTP-сервер можно написать примерно так:
Но это будет работать только для очень ограниченного диапазона HTTP-запросов и это не
учитывает всякие тонкости HTTP — persistent connections, request pipelining, content-coding, multipart и т.п.
Фантастика!
Думаю, Вы абсолютно правы.
Во всяком случае, Вы сейчас логику многих вещей разъяснили.
Вос всяком случае я еще немного по-спрашиваю Вас:
Если мы слушаем http-port, мы должны выключить веб-сервер, запущенный на этой же машине, и я понимаю, почему. Но меня смущает тот факт, например, что в это же время наш ( и не только наш) протокол слушает iptables (netflter). Возможно, они могут слушать его одновременно потому, что netfilter работает в ядре, тогда как быть с tcpdump? Получается, tcpdump может слушать вместе с apache, а моя программа — нет?
Whoa...I did a 'zcat /vmlinuz > /dev/audio' and I think I heard God...
Здравствуйте, Handler, Вы писали:
H>Фантастика! H>Думаю, Вы абсолютно правы. H>Во всяком случае, Вы сейчас логику многих вещей разъяснили. H>Вос всяком случае я еще немного по-спрашиваю Вас: H>Если мы слушаем http-port, мы должны выключить веб-сервер, запущенный на этой же машине, и я понимаю, почему. Но меня смущает тот факт, например, что в это же время наш ( и не только наш) протокол слушает iptables (netflter). Возможно, они могут слушать его одновременно потому, что netfilter работает в ядре, тогда как быть с tcpdump? Получается, tcpdump может слушать вместе с apache, а моя программа — нет?
У вас не верное представление о том что как работает и за что отвечает. Лучше будет если для какждой подсистемы вы сами хоть поверхностное описание прочитаете — это выработает в вас навок чтение документации и вылечет додумывание...
В общем настроение побольтать, поэтому метафора:
Представим ваш железный сервер — министерство.
Один из начальников — логика( скрипт ).
Секретарша — хттп-сервер .
Проходная и охрана — фаервол.
Курьер — TCP-сессия.
Действие.
Итак клиент делает запрос — отсылает курьера с листочком к начальнику в котором написано:
GET /document_about.html HTTP/1.1
Host: boss112.ministerstvo.ru
Курьер проходжит вначале на проходную( фаерволл ), — тут его шманают смотрят на него и могут либо пропустить, либо не пропустить — если к примеру на фаерволе есть правило никого из Быдло и Со не пропускать. В листочек притом не заглядывают — это не их пререгатива.
Дальше курьер шагает в открытый порт( дверь ) к секретарше и вручает ей запрос.
Секретарша смотрит на него и отвечает:
если босса нет на месте:
HTTP/1.1 404 Not Found
если босс бухой в сраку и несет белеберду:
HTTP/1.1 500 Internal Server Error
если босс в норме:
HTTP/1.1 200 Ok
"тело ответа"
или вообще может перенаправить( не помню код ) в другую дверь или министерство.
курьер несется назад с ответом...
Сказке конец.
Мораль:
— фаервол ничего нигде не слушает, а лишь пропускает или не пропускает на основе выданного ему предписания.
— тцпдампа в этой сказке нет — тк это видиокамеры, через которые админ может посмотреть что и куда бегает, но не может ответить вместо или подменить ответ.
— секретарша принимает записку не от охраны а от курьера напрямую — тцп сессия открывается с сервером, а не с фаерволлом.
— дальнейшие выводы делайте из документации.
Я буду Ваш ответ показывать как анекдот (в хорошем смысле).
По поводу ipatbles and tcpdump — был не прав, понял, что работают на разных уровнях модели OSI.
Кстати, кто на каких?
Whoa...I did a 'zcat /vmlinuz > /dev/audio' and I think I heard God...
Здравствуйте, Handler, Вы писали:
H>Я буду Ваш ответ показывать как анекдот (в хорошем смысле). H>По поводу ipatbles and tcpdump — был не прав, понял, что работают на разных уровнях модели OSI. H>Кстати, кто на каких?
Здравствуйте, Handler, Вы писали:
H>Если мы слушаем http-port, мы должны выключить веб-сервер, запущенный на этой же машине, и я понимаю, почему.
Да, но только если используется один и тот же порт. Это, думаю, понятно.
H>Но меня смущает тот факт, например, что в это же время наш ( и не только наш) протокол слушает iptables (netflter). Возможно, они могут слушать его одновременно потому, что netfilter работает в ядре, тогда как быть с tcpdump? Получается, tcpdump может слушать вместе с apache, а моя программа — нет?
Всякие прозрачные прокси-серверы и фаерволы, контролирующие прохождение данных по сети,
формально не являются частью модели OSI (хотя их присутствие сказывается на жизнеспособности
сети самым критическим образом).
И потом, прослушка протоколов может быть реализована очень хитрыми методами и на разных уровнях,
от прикладного до самых низких, и для этого вовсе необязательно создавать слушающий порт.
Я не специалист по *nix-системам, но в Windows, к примеру, путей много, вплоть до хаков ядра.
Поэтому то, что какой-то security-продукт свободно мониторит деятельность вашего сокета, не
будучи подсоединенным к нему, беспокоить не должно.
Тогда возникает закономерный вопрос: Зачем нам создавать пор, если мы можем поступать подобно прослушке? Таким образом, конечное решение зависит лишь от метода, который нам больше по душе
Whoa...I did a 'zcat /vmlinuz > /dev/audio' and I think I heard God...
Здравствуйте, Handler, Вы писали:
H>Тогда возникает закономерный вопрос: Зачем нам создавать пор, если мы можем поступать подобно прослушке? Таким образом, конечное решение зависит лишь от метода, который нам больше по душе
Разница в сложности реализации.
Создать сокет, перевести его в слушающий режим и принимать коннекты — это одно.
А написать полноценный сниффер или перехватчик трафика — это совсем другое.
Здравствуйте, Handler, Вы писали:
H>Тогда возникает закономерный вопрос: Зачем нам создавать пор, если мы можем поступать подобно прослушке? Таким образом, конечное решение зависит лишь от метода, который нам больше по душе
Вопросы человека напрочь игнорирующего документацию, и любящего окружающих. ***бали филосовствовать на тему... напишите хоть что-то, потом рассуждайте.
Для работы с сокетом нужно дергать несколько функций — открыть/закрыть, прочитать/записать( в первом приближении ). И не заботиться о гарантии доставке, целостности данных, фрагментации/дефрагментации, источнике/получателе, очередности, буферизации, приоритете, таймаутах, ... . Все ясно: коннект есть пока нет ошибок — пишем/читам.
Для создания подобия прослушки — с опусканием хотябы на один уровень должны будете для начала реализовать стек тцп( со всеми подсистемами ), еще ниже — стек ип( на все не менее нескольких месяцев ), + отладка и баги. В итоге получите те-же функции, + кучу потерянного времени и ящик неотловленных багов.
Нахрена делать то что уже за вас сделали и отладили, портировали на учу платформ, дали функции и хорошо описали все в документации на многих языках, включая русский.
Все-равно что пристрелить курьера и заставить секретаршу бегать ко всем клиентам самостоятельно.
int main (int argc, char * const argv[]) {
struct sockaddr_in addr_info;
int add_len = sizeof(addr_info);
int ret_addr, sock, n;
char* buf = new char[256];
Даже не могу сказать, что в ней не работает.
Если запускать в отладчике — то виснет на accept.
Если просто запустить — выполняется, ничего не происходит, не заканчивается.
Внутренний веб-сервер остановлен, обращаюсь к внутреннему хосту, а также к любому внешнему из браузера во время работы программы — ничего.
Когда мы указываем порт и адрес в структуре — их обязательно переводить функциями, или можно указать, как в моей программе?
И еще: как указать :
локальный хост?
конкретный хост?
Любой хост?
Пока все.
Whoa...I did a 'zcat /vmlinuz > /dev/audio' and I think I heard God...
Наконец-то заработало.
Здесь приведен участок кода, в котором программа слушает http-порт и читает данные, которые посылает ей браузер, если ему указать localhost, и затем делается попытка послать ответ браузеру (char* reply = "HTTP/1.1 403 Forbidden\r\n\0"
H>> n = write(sock, reply, strlen(reply)); P>первый параметр.
Да, я уже потом заметил — банальная ошибка не по невнимательности, а по отсутствию элементарного представления о том, что делаешь
P>на сем заканчиваю что-либо отвечать в этом посте.
Спасибо — помогли во многом разобраться.
Whoa...I did a 'zcat /vmlinuz > /dev/audio' and I think I heard God...
Теперь вопрос по процессам:
Предположим, я хочу, чтобы родительский процесс моей программы принимал запросы от клиентов (браузеров), и создавал для каждого из них дочерний процесс, который, в свою очередь, обрабатывал запрос и завершался, т.е.:
int main (int argc, char * const argv[]) {
sock = socket(AF_INET, SOCK_STREAM, 0);
bind(sock, (struct sockaddr*)&addr_info, sizeof(addr_info));
listen(sock, 1);
for (;) {
ret_addr = accept(sock, (struct sockaddr*)&addr_info, (socklen_t*)&add_len);
if (!fork()) { // child
close(sock);
// read
do {
n = read(ret_addr, buf, BUF_SIZE);
buf[n] = '\0';
cout << buf;
}
while (n==BUF_SIZE);
reply = "Child process: ";
out << getpid();
reply+= out.str();
n = write(ret_addr, reply.c_str(), reply.length());
if (errno) {perror("Errno: ");}
exit(0);
}
else { // parent
close(ret_addr);
}
}
close(sock);
return 0;
}
Такая программа обрабатывает первый запрос нормально, второй запрос обрабатывает, но в errno записывает код ошибки Bad file descriptor, ну а третий запрос вообще не обрабатывает.
Что тут не так?
Whoa...I did a 'zcat /vmlinuz > /dev/audio' and I think I heard God...
Здравствуйте, Handler,
ты не представляешь какой поимеешь рак моцга работая с голыми сокетами 8)
за 9 дней ты написал то что написал. впечатляет.
при использовании asio это пишется за 6 минут. и искаропки тебе сразу асинхронность+очередь_обработчиков+возможность использовать пул потоков, и много-много всякой вкуснятинки
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Оставьте на время попытки написать эту программу и займитесь теоретической составляющей.
Здесь столько ошибок, как технических, так и общего характера, которые произрастают из-за
недостаточного понимания предметной области, что можно очень долго продолжать эту тему, да
так ничего в конечном счете не получить.
Навскидку:
Принимая HTTP-поток, нельзя знать сколько байт отправит клиент.
Я, конечно, не знаю Ваших клиентов, но даже чтобы "проглотить" только заголовки, 256 байт недостаточно,
ибо один Cookie может достигать 4096 байт. read может банально повиснуть в цикле, потому что в HTTP/1.1
клиент не обязан закрывать свой конец соединения после отправки запроса, да и вообще HTTP нужно парсить
на лету, а не так как Вы это пытаетесь делать. А еще клиенты могут создавать два и более соединений
одновременно, причем одно из них будет оставаться пассивным некоторое время (нечто подобное происходит в
браузерах при запросе favicon). HTTP-сервер не должен поэтому быть синхронным, иначе он будет бесконечно
ждать данных по одному каналу, в то время как нужно обрабатывать другие. В ответе "403 forbidden" тоже
может быть тело, а в приведенном примере его нет, как нет и двух CRLF после статусной строки. Я уже не
говорю про всякие Content-Length, без которых клиент вообще не сможет прочитать тело ответа.
Это вкратце по мат.части HTTP.
Теперь по сокетам.
Передавать в listen единицу — автоматически обрекать свой сервер на простаивание в ожидании.
И это что у Вас ? Рестарт серверного сокета на каждый входящий коннект ? Оригинально, но не более.
Создавать, кстати, нужно дочерние потоки, а не процессы, а еще лучше задействовать пул потоков.
Ну и я не удивляюсь, что сервер не работает как надо, потому что реализация корявая, да еще
ошибки не проверяются, похоже.
Пожалуйста, без обид.
Это не укор, а попытка "дать пинка" в нужном направлении, в чем мы все иногда нуждаемся.
Разберитесь хотя бы с тем, как правильно писать простые серверы на сокетах (лучше асинхронные),
после этого многие вопросы отпадут, а такие грубые ошибки перестанут встречаться.
O>Создавать, кстати, нужно дочерние потоки, а не процессы, а еще лучше задействовать пул потоков.
В линукс нет понятия потоков — можно создать только процесс (все зависит от идеологии создаваемого процесса).
O>Пожалуйста, без обид. O>Это не укор, а попытка "дать пинка" в нужном направлении, в чем мы все иногда нуждаемся. O>Разберитесь хотя бы с тем, как правильно писать простые серверы на сокетах (лучше асинхронные), O>после этого многие вопросы отпадут, а такие грубые ошибки перестанут встречаться.
Именно это мне сейчас и нужно — поэтому я и продолжаю писать в эту тему
Whoa...I did a 'zcat /vmlinuz > /dev/audio' and I think I heard God...
Здравствуйте, Handler, Вы писали: H>В линукс нет понятия потоков — можно создать только процесс (все зависит от идеологии создаваемого процесса).
наглая ложь.
так было в ядрах 2.4.х
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Здравствуйте, niXman, Вы писали:
X>Здравствуйте, Handler, Вы писали: H>>В линукс нет понятия потоков — можно создать только процесс (все зависит от идеологии создаваемого процесса). X>наглая ложь. X>так было в ядрах 2.4.х
Вы имеете ввиду pthread_* ?
Согласен, ошибся. Я вообще в многопоточности ноль — это мой дебют.
По поводу boost.asio — не могу скомпилировать первый же пример
Выдает ошибки на этапе линковки — я не могу правильно собрать и прикрутить библиотеку boost.
Здравствуйте, Handler, Вы писали: H>Вы имеете ввиду pthread_* ?
угу.
H>По поводу boost.asio — не могу скомпилировать первый же пример H>Выдает ошибки на этапе линковки — я не могу правильно собрать и прикрутить библиотеку boost. H>"boost::system::generic_category()" H>"boost::system::system_category()"
к линковке добавь boost_system
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Здравствуйте, Аноним, Вы писали:
А>libboost_system.a А>libboost_filesystem.a
А>Все это есть — только счастья нет. А>Значит, что-то неправильно сделал: или библиотеку не так собрал, или подключил неправильно.
для начала разберись с основами сборки/линковки. потом программирование.
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Здравствуйте, niXman, Вы писали:
X>Здравствуйте, Аноним, Вы писали: А>>Что такое boost_system ? X>библиотека. libboost_filesystem
мля, libboost_system
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Re[20]: C++ listen tcp socket
От:
Аноним
Дата:
08.10.11 07:13
Оценка:
Ну и здорово: библиотеку в глаза не вижу, как слинковать проект с ней — тоже не знаю, пойду почитаю windows для чайников
Re[21]: C++ listen tcp socket
От:
Аноним
Дата:
09.10.11 22:03
Оценка:
Все офф мануалы прочитал, как по-писаному все сделал, библиотеки такой у меня нет, нигде ее найти не могу — интересно, как все работают с ней кроме меня?
Здравствуйте, Handler, Вы писали:
H>Если мы слушаем http-port, мы должны выключить веб-сервер, запущенный на этой же машине, и я понимаю, почему. Но меня смущает тот факт, например, что в это же время наш ( и не только наш) протокол слушает iptables (netflter). Возможно, они могут слушать его одновременно потому, что netfilter работает в ядре, тогда как быть с tcpdump? Получается, tcpdump может слушать вместе с apache, а моя программа — нет?
Здесь уместна следующая аналогия: у вас и у вашей престарелой соседки, очевидно, разные номера телефонов, чтобы люди, которые звонят кому-то из вас, попадали туда, куда целились. Однако КГБ может при этом слушать вас обоих, даже не имея (выделенного для этого) номера телефона
Здравствуйте, Аноним, Вы писали:
А>Все офф мануалы прочитал, как по-писаному все сделал, библиотеки такой у меня нет, нигде ее найти не могу — интересно, как все работают с ней кроме меня?
о чем речь?
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Вот это да! Почему все так просто оказалось? -lboost_system решил проблему. Не перестаю удивлять окружающих своей тупостью, впрочем, и себя тоже.
Спасибо.
Whoa...I did a 'zcat /vmlinuz > /dev/audio' and I think I heard God...
Здравствуйте, Handler, Вы писали:
H>Вот это да! Почему все так просто оказалось? -lboost_system решил проблему. Не перестаю удивлять окружающих своей тупостью, впрочем, и себя тоже. H>Спасибо.
Хватит насиловать человека boost'ом.
Он в трех соснах (listen bind accept) сишных функциях заблудился и понятия не имеет ни про синхронность асинхронность многопоточность и т.п.
Ему Стивенса читать надо стивенс unix взаимодействие процессов стивенс unix разработка сетевых приложений
+ man epoll
Когда осилит — будет писать обёртки на С++ когда их осилит почитает про boost.asio
К сожалению, у меня со стивенсом не срослось — первый же пример не скомпилился
Whoa...I did a 'zcat /vmlinuz > /dev/audio' and I think I heard God...
Re[28]: C++ listen tcp socket
От:
Аноним
Дата:
13.10.11 06:44
Оценка:
Как ни прискорбно — но с boost у меня тоже не срослось.
Итак, вернемся к самописному варианту tcp-сервера.
Как утверждает Стивенс (и не зря утверждает), "сервер" начинает слушать протокол и порт, который мы ему "натравили":
listen();
И далее принимает(или "засыпает", если очередь входящих сообщений пуста) входящие запросы от "клиента" (в нашем случае — веб-браузера):
accept();
(Дальше мои мысли)
Следовательно, как только accept() вернул нам валидный дескриптор:
if ( (session=accept(socket, buf, buf_len))!=-1 ) {/*valid handler*/}
мы можем создавать дочерний поток(процесс), который обработает запрос и завершится:
Простите, поторопился я с выводами — представленная мной схема оказалась вполне работоспособной.
Теперь скажите мне, почему session закрывается родителем?
Я, конечно, ноль в многопоточности, однако из прочитанной мной литературы о процессах сделал вывод, что с момента
fork()
и родитель, и его потомок начинают работать одновременно в одном и том же адресном пространстве (за последнее не ручаюсь). Как же потомок сможет читать/писать в session, если родитель, согласно логике программы, сразу же закроет дескриптор?
Подскажите, пожалуйста, в каком месте нарушена логика?
Whoa...I did a 'zcat /vmlinuz > /dev/audio' and I think I heard God...
Здравствуйте, Handler, Вы писали:
H>Простите, поторопился я с выводами — представленная мной схема оказалась вполне работоспособной.
H>Теперь скажите мне, почему session закрывается родителем? H>Я, конечно, ноль в многопоточности, однако из прочитанной мной литературы о процессах сделал вывод, что с момента H>fork() H>и родитель, и его потомок начинают работать одновременно в одном и том же адресном пространстве (за последнее не ручаюсь). Как же потомок сможет читать/писать в session, если родитель, согласно логике программы, сразу же закроет дескриптор? H>Подскажите, пожалуйста, в каком месте нарушена логика?
открой для себя man
разные процессы живут в разных адресных пространствах
fork создаёт новый процесс
если хочешь одно адресное пространство тебе надо создавать поток(нить, thread) в том же процессе.
Вот мой эксперемент 3х-летеней давновсти. Дыр куча — не проект а решето
Взял первый же пример из boost.asio — date_time, который посылает клиенту ответ. Так вот, я не смог прочитать от клиента сообщение.
Однако, это не заставило меня отказаться от boost вообще — только сейчас мне важнее разобраться с сокетами и потоками:
Первым делом — самолеты, ну а девушки — потом...
Whoa...I did a 'zcat /vmlinuz > /dev/audio' and I think I heard God...
Здравствуйте, Handler, Вы писали:
H>не смог прочитать от клиента сообщение.
там ведь пара: клиент и сервер. примеры все рабочие. так что, этого не может быть.
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Здравствуйте, Handler, Вы писали:
H>Взял первый же пример из boost.asio — date_time, который посылает клиенту ответ. Так вот, я не смог прочитать от клиента сообщение. H>Однако, это не заставило меня отказаться от boost вообще — только сейчас мне важнее разобраться с сокетами и потоками: H>Первым делом — самолеты, ну а девушки — потом...
Есть не только date_time. Есть примеры http-серверов.
Теперь встал еще один вопрос: Как отправить заголовок браузеру? Т.е.:
в php ч/з header(), а в с++ — ?
Начнем с самого простого, без чего, якобы, браузер вообще не сможет прочитать содержимое ответа (но, тем не менее, читает) — Content-length:
string str = "<html>...</html>";
string reply = "Content-length: "+str.length();
reply+= "\r\n\r\n"; // end of header
reply+= str;
Здесь все отлично — браузер отображает содержимое документа, причем сам заголовок в теле документа не отображается.
Далее хочу отправить кодировку в документ, т.к. документ у меня в cp-1251, а браузер — в utf-8 (default):
Какой же параметр устанавливает кодировку в заголовке?
google.com -> http header rfc -> http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html
Читаю:
14.2 Accept-Charset
Accept-Charset: iso-8859-5, unicode-1-1;q=0.8
14.17 Content-Type
Content-Type: text/html; charset=ISO-8859-4
Пишу:
Все равно не видит кодировку.
O>Клиент говорит серверу о том, в какой кодировке он желает получить ответ, с помощью Accept-Charset. O>Сервер обозначает кодировку ответа внутри Content-Type. Например: "Content-Type: text/html; charset=utf-8". O>Если кодировка не указывается, для HTML по умолчанию берется ISO-8859-1, а для XHTML — UTF-8.
Вот что сервер получает от клиента:
GET / HTTP/1.1
Host: localhost:8080
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_4) AppleWebKit/535.1+ (KHTML, like Gecko) Version/5.0 Safari/533.16
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: uk-ua
Accept-Encoding: gzip, deflate
Connection: keep-alive
Сервер отдает документ с правильным содержимым Content-Type.
O>Начинать нужно было не с форума, а отсюда:
O>Спецификации: O>RFC 1945 (HTTP 0.9-1.0) O>RFC 2616 (HTTP 1.1)
O>Книги: O>HTTP Developer's Handbook (C. Shiflett) O>HTTP: The Definitive Guide (D. Gourley, B. Totty, M. Sayer, S. Reddy, A. Aggarwal) O>Web-протоколы: теория и практика НТТР/1.1, взаимодействие протоколов, кэширование, измерение трафика O>(Б. Кришнамурти, Дж. Рексфорд)
много текста — про способы передачи кодировки сервером клиенту, не известные мне ничего не написано
Whoa...I did a 'zcat /vmlinuz > /dev/audio' and I think I heard God...
Тут не хватает заголовка Content-Type c нужным charset-ом.
H>Вот что сервер получает от клиента:
H>GET / HTTP/1.1 H>Host: localhost:8080 H>User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_4) AppleWebKit/535.1+ (KHTML, like Gecko) Version/5.0 Safari/533.16 H>Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 H>Accept-Language: uk-ua H>Accept-Encoding: gzip, deflate H>Connection: keep-alive
O>Тут не хватает заголовка Content-Type c нужным charset-ом.
Вот я сейчас не понял — как и где его не хватает? В str он есть, а в заголовок его не надо писать.
H>>GET / HTTP/1.1 H>>Host: localhost:8080 H>>User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_4) AppleWebKit/535.1+ (KHTML, like Gecko) Version/5.0 Safari/533.16 H>>Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 H>>Accept-Language: uk-ua H>>Accept-Encoding: gzip, deflate H>>Connection: keep-alive
O>А тут не хватает заголовка Accept-Charset.
что мне клиент прислал, то я и показал- все вопросы к веб-браузеру. Да и как, собственно, браузер может требовать кодировку? Его дело — запрашивать документ и отображать его содержимое. Возможно, я не совсем понимаю Ваших намеков.
Проблемы с кодировкой наблюдались у меня в случае, когда я делал так:
wget google.com/index.html
И далее использовал полученный файл, как документ.
Если же я самостоятельно напишу документ в текстовом редакторе по всем правилам указания кодировок — таких проблем не возникает.
Теперь усложним задачу:
Для начала заметим, что значение дескриптора socket и accept в программе:
sock = socket(...);//4
session = accept(sock, ...); // 5
Теперь запустим нашу программу как демон из другой програмы:
if(!fork()) execl("myprog", argv);
Наша программа успешно запустилась и ждет входящих сообщений, но не обрабатывает их (т.е. по-просту, не работатет).
И почему-то указанные выше sock и session на 1 меньше:
sock = socket(...);//3
session = accept(sock, ...); // 4
Что тут не так?
Whoa...I did a 'zcat /vmlinuz > /dev/audio' and I think I heard God...
Здравствуйте, Handler, Вы писали:
O>>Тут не хватает заголовка Content-Type c нужным charset-ом.
H>Вот я сейчас не понял — как и где его не хватает? В str он есть, а в заголовок его не надо писать.
У веб-сервера, который отдает HTML-страницу, есть два места для указания кодировки.
Первое, и главное место, — это заголовок HTTP-ответа Content-Type.
В нем указывается MIME-тип документа и его кодировка.
Например: "Content-Type: text/html; charset=Windows-1251".
Второе место находится внутри самого HTML — это атрибуты элемента <meta>.
Но браузер не обязан на них смотреть. По спецификации HTTP (RFC 2616, Chapter 3.4.1),
если кодировка не указывается в заголовке Content-Type, по умолчанию принимается ISO-8859-1,
и наплевать что там внутри <meta>.
H>что мне клиент прислал, то я и показал- все вопросы к веб-браузеру. Да и как, собственно, браузер может требовать кодировку? Его дело — запрашивать документ и отображать его содержимое. Возможно, я не совсем понимаю Ваших намеков.
Браузер может запрашивать не только кодировку, но и язык, способ компрессии, метод передачи и другие данные.
Например, если Вы зайдете на Google из Китая, увидите главную страницу с иероглифами.
Вопрос — как это достигается ? Отнюдь не по айпи. Когда браузер шлет запрос серверу, в этом запросе
обычно указываются некоторые "пожелания":
Accept: text/html — хочу получить такую веб-страницу,
Accept-Language: ru — чтоб контент был на русском,
Accept-Charset: Windows-1251 — и чтоб все это было в кодировке Windows-1251,
Accept-Encoding: x-gzip — пусть сервер в целях экономии трафика пожмет страницу GZip-ом.
Если сервер в состоянии удовлетворить такие пожелания, он вернет нужный контент.
Если нет, будет ответ 400 (Bad Request), 406 (Not Accepted), или что-то в этом роде.
Само собой, браузер, установленный на компьютере с китайской локализацией операционной системы,
или настроенный на такую локализацию, будет слать запросы с другими Accept-ами и получать от
сервера данные в других языках и кодировках.
В приведенном коде эта техника игнорируется, поэтому результаты не совпадают с ожиданиями.
H>Проблемы с кодировкой наблюдались у меня в случае, когда я делал так:
H>wget google.com/index.html H>И далее использовал полученный файл, как документ. H>Если же я самостоятельно напишу документ в текстовом редакторе по всем правилам указания кодировок — таких проблем не возникает.
Я пока вижу только одну проблему — HTTP-запросы и ответы игнорируют заголовки Accept-Charset и Content-Type.
H>Теперь усложним задачу: H>Для начала заметим, что значение дескриптора socket и accept в программе: H>sock = socket(...);//4 H>session = accept(sock, ...); // 5
H>Теперь запустим нашу программу как демон из другой програмы: H>if(!fork()) execl("myprog", argv);
H>Наша программа успешно запустилась и ждет входящих сообщений, но не обрабатывает их (т.е. по-просту, не работатет). H>И почему-то указанные выше sock и session на 1 меньше: H>sock = socket(...);//3 H>session = accept(sock, ...); // 4
H>Что тут не так?
Ну например, из-за того, что обе копии программы биндят сокет на один и тот же порт (8080).
H>Создать приложение демон-процесс, слушающий и обрабатывающий запросы к TCP порту основанные на HTTP, выдающий в результате обработки запроса HTML-контент взятый из базы данных mysql, выполняющий перекодирование выдаваемого контента в желаемую/затребованную кодировку, которая устанавливается либо в самом запросе, либо в настройках его инициализационных параметров.
Для перекодирования текстового содержимого нужно использовать сторонние библиотеки.
Например, iconv. Лично я предпочитаю библиотеку ICU.
Логика работы веб-сервера тогда будет примерно следующей:
Принимаем HTTP-запрос, вытаскиваем из заголовка "Accept-Charset" кодировку (или берем ее
из настроек нашего веб-сервера), затем добываем HTML-контент из базы данных, перегоняем
его в нужную кодировку, после чего формируем заголовки ответа, не забыв про Content-Type и
charset, и в полученном виде отдаем клиенту.