Re[33]: C++ listen tcp socket
От: okman Беларусь https://searchinform.ru/
Дата: 17.10.11 14:23
Оценка: 2 (1)
Здравствуйте, 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, между тем, не такой уж и примитивный протокол, и в нем не все лежит на поверхности.

Начинать нужно было не с форума, а отсюда:

Спецификации:
RFC 1945 (HTTP 0.9-1.0)
RFC 2616 (HTTP 1.1)

Книги:
HTTP Developer's Handbook (C. Shiflett)
HTTP: The Definitive Guide (D. Gourley, B. Totty, M. Sayer, S. Reddy, A. Aggarwal)
Web-протоколы: теория и практика НТТР/1.1, взаимодействие протоколов, кэширование, измерение трафика
(Б. Кришнамурти, Дж. Рексфорд)
Re: C++ listen tcp socket
От: pavard  
Дата: 28.09.11 06:12
Оценка: :)
весь инет засрали этим вопросом.

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 ); // ----- // -----
}
C++ listen tcp socket
От: Handler Украина  
Дата: 27.09.11 23:22
Оценка:
Здравствуйте!
Задача:
Создать приложение демон-процесс, слушающий и обрабатывающий запросы к 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];

bzero(&addr_info, sizeof(addr_info));
addr_info.sin_family = AF_INET;
addr_info.sin_port = 8080;
addr_info.sin_addr.s_addr = INADDR_ANY;

sock_id = socket(AF_INET, SOCK_STREAM, 0);
if (sock_id==-1) {cout<< "Error create socket\n"; return -1;}
if (bind(sock_id, (struct sockaddr*)&addr_info, sizeof(addr_info))==-1) {cout<< "Error bind\n"; return -1;}
listen(sock_id, 5);
ret_addr = recv(sock_id, buf, 256, 0);
// ret_addr = accept(sock_id, (struct sockaddr*)&addr_info, (socklen_t*)&add_len);
return 0;
}

Но я так понимаю, что это совсем не в ту сторону. Единственное, что тут правильно — это socket().
Пожалуйста, подскажите схему приложения-реализации данной задачи, что за чем следует, а я постараюсь по Вашей схеме написать реализацию.
Заранее благодарен.
Алексей

28.09.11 13:56: Перенесено модератором из 'C/C++' — Odi$$ey
Whoa...I did a 'zcat /vmlinuz > /dev/audio' and I think I heard God...
Re: C++ listen tcp socket
От: niXman Ниоткуда https://github.com/niXman
Дата: 27.09.11 23:58
Оценка:
Здравствуйте, Handler, Вы писали:

H>К сожалению, никогда не писал С++ программ

в вашем коде, из с++, только new и cout. так что программа написана на Си.
смотрите boost.asio.
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Re: C++ listen tcp socket
От: placement_new  
Дата: 28.09.11 02:49
Оценка:
Здравствуйте, Handler, Вы писали:

Возьмите книжку Стивенса по сетевым приложениям.
Прочитайте оттуда буквально три первые главы (100 стр.) — и все вопросы отпадут.
PS: boost.asio смотреть рано.
Re: C++ listen tcp socket
От: Handler Украина  
Дата: 28.09.11 09:32
Оценка:
Меня смущает тот факт, что все примеры, которые я встречал, описывают клиент-серверную модель, а мне, скорее всего нужна модель типа tcpdump.
Спасибо, что дали направление
Whoa...I did a 'zcat /vmlinuz > /dev/audio' and I think I heard God...
Re[2]: C++ listen tcp socket
От: niXman Ниоткуда https://github.com/niXman
Дата: 28.09.11 09:33
Оценка:
Здравствуйте, pavard, Вы писали:
P>0) болт кладем на вух ораторов выше( пока руками не научитесь пользоваться — обертки будут лишь дурманющим разум зельмем ).
ох уж эти велокодеры.. они такие забавные 8)
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Re[2]: C++ listen tcp socket
От: pavard  
Дата: 28.09.11 11:46
Оценка:
Вердикт — сами не знаете что хотите.

Нет такой модели tcpdump. Отдавать контент по хттп — дело сервера, запрашивать этот контент — дело клиента. Отсюда и название клиент-серверное.
Название tcpdump = tcp + dump = сдампь чтоб я посмотрел что там бегает = тупо утилита чтоб посмотреть.

В общем, проще будет пойти от главного — разобраться в целях. И зрите не в список целей написать то-то то-то, а в список — я не понимаю того-то того-то.
Re: C++ listen tcp socket
От: okman Беларусь https://searchinform.ru/
Дата: 28.09.11 12:27
Оценка:
Здравствуйте, 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-сервер можно написать примерно так:
SOCKET Sock = socket(...);
bind(Sock, ...);
listen(Sock, ...);

SOCKET AccSock = accept(Sock, ...);
recv(AccSock, pBuffer, ...);
//...
send(AccSock, "HTTP/1.0 200 OK\r\n\r\nContent-Type:text/html\r\nContent-Length: 53\r\n\r\n<html><head></head><body><h1>Hello</h1></body></html>", ...);
shutdown(AccSock, SD_SEND);
closesocket(AccSock);
closesocket(Sock);


Но это будет работать только для очень ограниченного диапазона HTTP-запросов и это не
учитывает всякие тонкости HTTP — persistent connections, request pipelining, content-coding, multipart и т.п.
Re[2]: C++ listen tcp socket
От: Handler Украина  
Дата: 29.09.11 06:08
Оценка:
Фантастика!
Думаю, Вы абсолютно правы.
Во всяком случае, Вы сейчас логику многих вещей разъяснили.
Вос всяком случае я еще немного по-спрашиваю Вас:
Если мы слушаем http-port, мы должны выключить веб-сервер, запущенный на этой же машине, и я понимаю, почему. Но меня смущает тот факт, например, что в это же время наш ( и не только наш) протокол слушает iptables (netflter). Возможно, они могут слушать его одновременно потому, что netfilter работает в ядре, тогда как быть с tcpdump? Получается, tcpdump может слушать вместе с apache, а моя программа — нет?
Whoa...I did a 'zcat /vmlinuz > /dev/audio' and I think I heard God...
Re[3]: C++ listen tcp socket
От: pavard  
Дата: 29.09.11 09:16
Оценка:
Здравствуйте, 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

"тело ответа"


или вообще может перенаправить( не помню код ) в другую дверь или министерство.

курьер несется назад с ответом...

Сказке конец.

Мораль:
— фаервол ничего нигде не слушает, а лишь пропускает или не пропускает на основе выданного ему предписания.
— тцпдампа в этой сказке нет — тк это видиокамеры, через которые админ может посмотреть что и куда бегает, но не может ответить вместо или подменить ответ.
— секретарша принимает записку не от охраны а от курьера напрямую — тцп сессия открывается с сервером, а не с фаерволлом.
— дальнейшие выводы делайте из документации.
Re[4]: C++ listen tcp socket
От: Handler Украина  
Дата: 29.09.11 09:22
Оценка:
Я буду Ваш ответ показывать как анекдот (в хорошем смысле).
По поводу ipatbles and tcpdump — был не прав, понял, что работают на разных уровнях модели OSI.
Кстати, кто на каких?
Whoa...I did a 'zcat /vmlinuz > /dev/audio' and I think I heard God...
Re[5]: C++ listen tcp socket
От: pavard  
Дата: 29.09.11 09:31
Оценка:
Здравствуйте, Handler, Вы писали:

H>Я буду Ваш ответ показывать как анекдот (в хорошем смысле).

H>По поводу ipatbles and tcpdump — был не прав, понял, что работают на разных уровнях модели OSI.
H>Кстати, кто на каких?

rtfm.
Re[3]: C++ listen tcp socket
От: okman Беларусь https://searchinform.ru/
Дата: 29.09.11 10:11
Оценка:
Здравствуйте, Handler, Вы писали:

H>Если мы слушаем http-port, мы должны выключить веб-сервер, запущенный на этой же машине, и я понимаю, почему.


Да, но только если используется один и тот же порт. Это, думаю, понятно.

H>Но меня смущает тот факт, например, что в это же время наш ( и не только наш) протокол слушает iptables (netflter). Возможно, они могут слушать его одновременно потому, что netfilter работает в ядре, тогда как быть с tcpdump? Получается, tcpdump может слушать вместе с apache, а моя программа — нет?


Всякие прозрачные прокси-серверы и фаерволы, контролирующие прохождение данных по сети,
формально не являются частью модели OSI (хотя их присутствие сказывается на жизнеспособности
сети самым критическим образом).

И потом, прослушка протоколов может быть реализована очень хитрыми методами и на разных уровнях,
от прикладного до самых низких, и для этого вовсе необязательно создавать слушающий порт.
Я не специалист по *nix-системам, но в Windows, к примеру, путей много, вплоть до хаков ядра.
Поэтому то, что какой-то security-продукт свободно мониторит деятельность вашего сокета, не
будучи подсоединенным к нему, беспокоить не должно.
Re[4]: C++ listen tcp socket
От: Handler Украина  
Дата: 30.09.11 09:37
Оценка:
Тогда возникает закономерный вопрос: Зачем нам создавать пор, если мы можем поступать подобно прослушке? Таким образом, конечное решение зависит лишь от метода, который нам больше по душе
Whoa...I did a 'zcat /vmlinuz > /dev/audio' and I think I heard God...
Re[5]: C++ listen tcp socket
От: okman Беларусь https://searchinform.ru/
Дата: 30.09.11 09:44
Оценка:
Здравствуйте, Handler, Вы писали:

H>Тогда возникает закономерный вопрос: Зачем нам создавать пор, если мы можем поступать подобно прослушке? Таким образом, конечное решение зависит лишь от метода, который нам больше по душе


Разница в сложности реализации.
Создать сокет, перевести его в слушающий режим и принимать коннекты — это одно.
А написать полноценный сниффер или перехватчик трафика — это совсем другое.
Re[5]: C++ listen tcp socket
От: pavard  
Дата: 30.09.11 12:22
Оценка:
Здравствуйте, Handler, Вы писали:

H>Тогда возникает закономерный вопрос: Зачем нам создавать пор, если мы можем поступать подобно прослушке? Таким образом, конечное решение зависит лишь от метода, который нам больше по душе


Вопросы человека напрочь игнорирующего документацию, и любящего окружающих. ***бали филосовствовать на тему... напишите хоть что-то, потом рассуждайте.

Для работы с сокетом нужно дергать несколько функций — открыть/закрыть, прочитать/записать( в первом приближении ). И не заботиться о гарантии доставке, целостности данных, фрагментации/дефрагментации, источнике/получателе, очередности, буферизации, приоритете, таймаутах, ... . Все ясно: коннект есть пока нет ошибок — пишем/читам.

Для создания подобия прослушки — с опусканием хотябы на один уровень должны будете для начала реализовать стек тцп( со всеми подсистемами ), еще ниже — стек ип( на все не менее нескольких месяцев ), + отладка и баги. В итоге получите те-же функции, + кучу потерянного времени и ящик неотловленных багов.

Нахрена делать то что уже за вас сделали и отладили, портировали на учу платформ, дали функции и хорошо описали все в документации на многих языках, включая русский.

Все-равно что пристрелить курьера и заставить секретаршу бегать ко всем клиентам самостоятельно.
Re[6]: C++ listen tcp socket
От: Handler Украина  
Дата: 04.10.11 01:13
Оценка:
Вот моя программа:
#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

using namespace std;

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];

// socket
bzero(&addr_info, sizeof(addr_info));
addr_info.sin_family = AF_INET;
addr_info.sin_port = 80;
addr_info.sin_addr.s_addr = inet_addr("127.0.0.1");//INADDR_ANY;
sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock==-1) {cout<< "Error create socket\n"; return -1;}
// bind
if (bind(sock, (struct sockaddr*)&addr_info, sizeof(addr_info))==-1) {cout<< "Error bind\n"; close(sock); return -1;}

// listen
if (!listen(sock, 5)) {
ret_addr = accept(sock, (struct sockaddr*)&addr_info, (socklen_t*)&add_len);
n = read(ret_addr, buf, 255);
// ret_addr = recv(sock, buf, 256, 0);
cout << buf << "\n";
}
else {
cout << "Error listen ";
}
close(sock);

return 0;
}

Даже не могу сказать, что в ней не работает.
Если запускать в отладчике — то виснет на accept.
Если просто запустить — выполняется, ничего не происходит, не заканчивается.
Внутренний веб-сервер остановлен, обращаюсь к внутреннему хосту, а также к любому внешнему из браузера во время работы программы — ничего.
Когда мы указываем порт и адрес в структуре — их обязательно переводить функциями, или можно указать, как в моей программе?
И еще: как указать :
локальный хост?
конкретный хост?
Любой хост?
Пока все.
Whoa...I did a 'zcat /vmlinuz > /dev/audio' and I think I heard God...
Re[7]: C++ listen tcp socket
От: pavard  
Дата: 04.10.11 12:07
Оценка:
Здравствуйте, Handler, Вы писали:

H>addr_info.sin_port = 80;

addr_info.sin_port = htons( 80 );

и проверте что программа запускается из под рута. в юнихах порты до 1024 может открывать только рут.
Re[8]: C++ listen tcp socket
От: Handler Украина  
Дата: 05.10.11 05:58
Оценка:
Наконец-то заработало.
Здесь приведен участок кода, в котором программа слушает http-порт и читает данные, которые посылает ей браузер, если ему указать localhost, и затем делается попытка послать ответ браузеру (char* reply = "HTTP/1.1 403 Forbidden\r\n\0"

if (!listen(sock, 5)) {
ret_addr = accept(sock, (struct sockaddr*)&addr_info, (socklen_t*)&add_len);
n = read(ret_addr, buf, 255);
buf[255] = '\0';
n = write(sock, reply, strlen(reply));
cout << errno << endl;
cout << buf << "\n";
}

чтение возвращает -1, errno=57 — Socket is not connected.
Что я делаю не так?
Whoa...I did a 'zcat /vmlinuz > /dev/audio' and I think I heard God...
Re[9]: C++ listen tcp socket
От: pavard  
Дата: 05.10.11 07:41
Оценка:
H>if (!listen(sock, 5)) {
H> ret_addr = accept(sock, (struct sockaddr*)&addr_info, (socklen_t*)&add_len);
H> n = read(ret_addr, buf, 255);
тут надо проверять на ошибку( n == -1 ) и брать errno — дальше она перетерается write'ом.

H> buf[255] = '\0';

buf[n]='\0';

H> n = write(sock, reply, strlen(reply));

первый параметр.

H> cout << errno << endl;

это ошибка от write.

H> cout << buf << "\n";

H>}

на сем заканчиваю что-либо отвечать в этом посте.
Re[10]: C++ listen tcp socket
От: Handler Украина  
Дата: 06.10.11 06:14
Оценка:
H>> n = write(sock, reply, strlen(reply));
P>первый параметр.

Да, я уже потом заметил — банальная ошибка не по невнимательности, а по отсутствию элементарного представления о том, что делаешь

P>на сем заканчиваю что-либо отвечать в этом посте.


Спасибо — помогли во многом разобраться.
Whoa...I did a 'zcat /vmlinuz > /dev/audio' and I think I heard God...
Re[11]: C++ listen tcp socket
От: Handler Украина  
Дата: 07.10.11 06:28
Оценка:
Теперь вопрос по процессам:
Предположим, я хочу, чтобы родительский процесс моей программы принимал запросы от клиентов (браузеров), и создавал для каждого из них дочерний процесс, который, в свою очередь, обрабатывал запрос и завершался, т.е.:

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...
Re[12]: C++ listen tcp socket
От: niXman Ниоткуда https://github.com/niXman
Дата: 07.10.11 06:46
Оценка:
Здравствуйте, Handler,
ты не представляешь какой поимеешь рак моцга работая с голыми сокетами 8)
за 9 дней ты написал то что написал. впечатляет.
при использовании asio это пишется за 6 минут. и искаропки тебе сразу асинхронность+очередь_обработчиков+возможность использовать пул потоков, и много-много всякой вкуснятинки
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Re[12]: C++ listen tcp socket
От: okman Беларусь https://searchinform.ru/
Дата: 07.10.11 06:57
Оценка:
Handler, разрешите дать Вам добрый совет.

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

Навскидку:
Принимая HTTP-поток, нельзя знать сколько байт отправит клиент.
Я, конечно, не знаю Ваших клиентов, но даже чтобы "проглотить" только заголовки, 256 байт недостаточно,
ибо один Cookie может достигать 4096 байт. read может банально повиснуть в цикле, потому что в HTTP/1.1
клиент не обязан закрывать свой конец соединения после отправки запроса, да и вообще HTTP нужно парсить
на лету, а не так как Вы это пытаетесь делать. А еще клиенты могут создавать два и более соединений
одновременно, причем одно из них будет оставаться пассивным некоторое время (нечто подобное происходит в
браузерах при запросе favicon). HTTP-сервер не должен поэтому быть синхронным, иначе он будет бесконечно
ждать данных по одному каналу, в то время как нужно обрабатывать другие. В ответе "403 forbidden" тоже
может быть тело, а в приведенном примере его нет, как нет и двух CRLF после статусной строки. Я уже не
говорю про всякие Content-Length, без которых клиент вообще не сможет прочитать тело ответа.
Это вкратце по мат.части HTTP.

Теперь по сокетам.
Передавать в listen единицу — автоматически обрекать свой сервер на простаивание в ожидании.
И это что у Вас ? Рестарт серверного сокета на каждый входящий коннект ? Оригинально, но не более.
Создавать, кстати, нужно дочерние потоки, а не процессы, а еще лучше задействовать пул потоков.
Ну и я не удивляюсь, что сервер не работает как надо, потому что реализация корявая, да еще
ошибки не проверяются, похоже.

Пожалуйста, без обид.
Это не укор, а попытка "дать пинка" в нужном направлении, в чем мы все иногда нуждаемся.
Разберитесь хотя бы с тем, как правильно писать простые серверы на сокетах (лучше асинхронные),
после этого многие вопросы отпадут, а такие грубые ошибки перестанут встречаться.
Re[13]: C++ listen tcp socket
От: Handler Украина  
Дата: 07.10.11 09:38
Оценка:
O>Создавать, кстати, нужно дочерние потоки, а не процессы, а еще лучше задействовать пул потоков.
В линукс нет понятия потоков — можно создать только процесс (все зависит от идеологии создаваемого процесса).

O>Пожалуйста, без обид.

O>Это не укор, а попытка "дать пинка" в нужном направлении, в чем мы все иногда нуждаемся.
O>Разберитесь хотя бы с тем, как правильно писать простые серверы на сокетах (лучше асинхронные),
O>после этого многие вопросы отпадут, а такие грубые ошибки перестанут встречаться.

Именно это мне сейчас и нужно — поэтому я и продолжаю писать в эту тему
Whoa...I did a 'zcat /vmlinuz > /dev/audio' and I think I heard God...
Re[14]: C++ listen tcp socket
От: niXman Ниоткуда https://github.com/niXman
Дата: 07.10.11 09:53
Оценка:
Здравствуйте, Handler, Вы писали:
H>В линукс нет понятия потоков — можно создать только процесс (все зависит от идеологии создаваемого процесса).
наглая ложь.
так было в ядрах 2.4.х
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Re[15]: C++ listen tcp socket
От: Handler Украина  
Дата: 07.10.11 11:23
Оценка:
Здравствуйте, niXman, Вы писали:

X>Здравствуйте, Handler, Вы писали:

H>>В линукс нет понятия потоков — можно создать только процесс (все зависит от идеологии создаваемого процесса).
X>наглая ложь.
X>так было в ядрах 2.4.х

Вы имеете ввиду pthread_* ?
Согласен, ошибся. Я вообще в многопоточности ноль — это мой дебют.

По поводу boost.asio — не могу скомпилировать первый же пример
Выдает ошибки на этапе линковки — я не могу правильно собрать и прикрутить библиотеку boost.

"boost::system::generic_category()"
"boost::system::system_category()"
Whoa...I did a 'zcat /vmlinuz > /dev/audio' and I think I heard God...
Re[16]: C++ listen tcp socket
От: niXman Ниоткуда https://github.com/niXman
Дата: 07.10.11 11:41
Оценка:
Здравствуйте, Handler, Вы писали:
H>Вы имеете ввиду pthread_* ?
угу.

H>По поводу boost.asio — не могу скомпилировать первый же пример

H>Выдает ошибки на этапе линковки — я не могу правильно собрать и прикрутить библиотеку boost.
H>"boost::system::generic_category()"
H>"boost::system::system_category()"
к линковке добавь boost_system
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Re[17]: C++ listen tcp socket
От: Аноним  
Дата: 07.10.11 21:17
Оценка:
X>к линковке добавь boost_system

Поставил библиотеку boost: /usr/src/boost
Add header files path: /usr/src/boost
Library search path: /usr/include/boost/stage/lib

Что такое boost_system ?
Re[18]: C++ listen tcp socket
От: niXman Ниоткуда https://github.com/niXman
Дата: 07.10.11 21:41
Оценка:
Здравствуйте, Аноним, Вы писали:
А>Что такое boost_system ?
библиотека. libboost_filesystem
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Re[19]: C++ listen tcp socket
От: Аноним  
Дата: 07.10.11 22:03
Оценка:
libboost_system.a
libboost_filesystem.a

Все это есть — только счастья нет.
Значит, что-то неправильно сделал: или библиотеку не так собрал, или подключил неправильно.
Re[20]: C++ listen tcp socket
От: niXman Ниоткуда https://github.com/niXman
Дата: 07.10.11 22:53
Оценка:
Здравствуйте, Аноним, Вы писали:

А>libboost_system.a

А>libboost_filesystem.a

А>Все это есть — только счастья нет.

А>Значит, что-то неправильно сделал: или библиотеку не так собрал, или подключил неправильно.
для начала разберись с основами сборки/линковки. потом программирование.
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Re[19]: C++ listen tcp socket
От: niXman Ниоткуда https://github.com/niXman
Дата: 07.10.11 22:54
Оценка:
Здравствуйте, 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
Оценка:
Все офф мануалы прочитал, как по-писаному все сделал, библиотеки такой у меня нет, нигде ее найти не могу — интересно, как все работают с ней кроме меня?
Re[3]: C++ listen tcp socket
От: Pzz Россия https://github.com/alexpevzner
Дата: 09.10.11 23:11
Оценка:
Здравствуйте, Handler, Вы писали:

H>Если мы слушаем http-port, мы должны выключить веб-сервер, запущенный на этой же машине, и я понимаю, почему. Но меня смущает тот факт, например, что в это же время наш ( и не только наш) протокол слушает iptables (netflter). Возможно, они могут слушать его одновременно потому, что netfilter работает в ядре, тогда как быть с tcpdump? Получается, tcpdump может слушать вместе с apache, а моя программа — нет?


Здесь уместна следующая аналогия: у вас и у вашей престарелой соседки, очевидно, разные номера телефонов, чтобы люди, которые звонят кому-то из вас, попадали туда, куда целились. Однако КГБ может при этом слушать вас обоих, даже не имея (выделенного для этого) номера телефона
Re[22]: C++ listen tcp socket
От: niXman Ниоткуда https://github.com/niXman
Дата: 09.10.11 23:13
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Все офф мануалы прочитал, как по-писаному все сделал, библиотеки такой у меня нет, нигде ее найти не могу — интересно, как все работают с ней кроме меня?

о чем речь?
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Re[23]: C++ listen tcp socket
От: Handler Украина  
Дата: 10.10.11 08:11
Оценка:
1. Ввел в google "boost asio"
2. зашел на страницу библиотеки boost asio и скачал boost_1_47_0.tar.bz2
3. распаковал, скопировал в /usr/include/boost
4. ./bootstrap.sh
5. ./bjam --with-system --with-thread --with-date_time --with-regex --with-serialization stage
6. Sample code > test.cpp
7. c++ -I /usr/include/boost -L/usr/include/boost/stage/lib/ -o test test.cpp

Undefined symbols:
"boost::system::generic_category()", referenced from:
__static_initialization_and_destruction_0(int, int)in ccU5PXV4.o
__static_initialization_and_destruction_0(int, int)in ccU5PXV4.o
"boost::system::system_category()", referenced from:
boost::asio::error::get_system_category() in ccU5PXV4.o
boost::system::error_code::error_code()in ccU5PXV4.o
__static_initialization_and_destruction_0(int, int)in ccU5PXV4.o
ld: symbol(s) not found
collect2: ld returned 1 exit status
Whoa...I did a 'zcat /vmlinuz > /dev/audio' and I think I heard God...
Re[24]: C++ listen tcp socket
От: niXman Ниоткуда https://github.com/niXman
Дата: 10.10.11 08:26
Оценка:
Здравствуйте, Handler,
к линковке добавь boost.system. повторяюсь уже.
"-lboost_system"
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Re[24]: C++ listen tcp socket
От: niXman Ниоткуда https://github.com/niXman
Дата: 10.10.11 08:28
Оценка:
Здравствуйте, Handler, Вы писали:
H>3. ..., скопировал в /usr/include/boost
жестоко вы это..
> ./bjam release install --prefix=/usr/local
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Re[25]: C++ listen tcp socket
От: Handler Украина  
Дата: 10.10.11 09:35
Оценка:
Вот это да! Почему все так просто оказалось? -lboost_system решил проблему. Не перестаю удивлять окружающих своей тупостью, впрочем, и себя тоже.
Спасибо.
Whoa...I did a 'zcat /vmlinuz > /dev/audio' and I think I heard God...
Re[26]: C++ listen tcp socket
От: yurror Россия  
Дата: 10.10.11 11:53
Оценка:
Здравствуйте, Handler, Вы писали:

H>Вот это да! Почему все так просто оказалось? -lboost_system решил проблему. Не перестаю удивлять окружающих своей тупостью, впрочем, и себя тоже.

H>Спасибо.
Хватит насиловать человека boost'ом.
Он в трех соснах (listen bind accept) сишных функциях заблудился и понятия не имеет ни про синхронность асинхронность многопоточность и т.п.
Ему Стивенса читать надо
стивенс unix взаимодействие процессов
стивенс unix разработка сетевых приложений
+ man epoll
Когда осилит — будет писать обёртки на С++ когда их осилит почитает про boost.asio
Re[27]: C++ listen tcp socket
От: Handler Украина  
Дата: 11.10.11 09:32
Оценка:
К сожалению, у меня со стивенсом не срослось — первый же пример не скомпилился
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*/}
мы можем создавать дочерний поток(процесс), который обработает запрос и завершится:
listen();
for (;;) {
accept();
if ( (session=accept(socket, buf, buf_len))!=-1 ) {
if(!fork()) {/*child*/do smth; exit(0);}
else        {/*parent*/ close(session);}
}
}


Такая схема не работает.
Подскажите, пожалуйста, в каком месте нарушена логика?
Re[29]: C++ listen tcp socket
От: Handler Украина  
Дата: 13.10.11 06:58
Оценка:
Простите, поторопился я с выводами — представленная мной схема оказалась вполне работоспособной.

Теперь скажите мне, почему session закрывается родителем?
Я, конечно, ноль в многопоточности, однако из прочитанной мной литературы о процессах сделал вывод, что с момента
fork()
и родитель, и его потомок начинают работать одновременно в одном и том же адресном пространстве (за последнее не ручаюсь). Как же потомок сможет читать/писать в session, если родитель, согласно логике программы, сразу же закроет дескриптор?
Подскажите, пожалуйста, в каком месте нарушена логика?
Whoa...I did a 'zcat /vmlinuz > /dev/audio' and I think I heard God...
Re[30]: C++ listen tcp socket
От: yurror Россия  
Дата: 13.10.11 08:07
Оценка:
Здравствуйте, Handler, Вы писали:

H>Простите, поторопился я с выводами — представленная мной схема оказалась вполне работоспособной.


H>Теперь скажите мне, почему session закрывается родителем?

H>Я, конечно, ноль в многопоточности, однако из прочитанной мной литературы о процессах сделал вывод, что с момента
H>fork()
H>и родитель, и его потомок начинают работать одновременно в одном и том же адресном пространстве (за последнее не ручаюсь). Как же потомок сможет читать/писать в session, если родитель, согласно логике программы, сразу же закроет дескриптор?
H>Подскажите, пожалуйста, в каком месте нарушена логика?
открой для себя man
разные процессы живут в разных адресных пространствах
fork создаёт новый процесс
если хочешь одно адресное пространство тебе надо создавать поток(нить, thread) в том же процессе.
Вот мой эксперемент 3х-летеней давновсти. Дыр куча — не проект а решето

http_buffer.c
#include <http_buffer.h>

#include <sys/socket.h>
#include <stdlib.h>
#include <string.h>

/* HTTP Buffer Block Functions */

http_buffer_block *http_make_buffer_block(size_t length, const char *data)
{
    http_buffer_block *res = (http_buffer_block *)malloc(sizeof(http_buffer_block));
    res->data = (char*)malloc(res->length = length);
    memcpy(res->data, data, length);
    res->next = NULL;
    return res;
}

size_t http_buffer_block_cat(http_buffer_block *block, char *dst, size_t length)
{
    size_t size;
    char *buf;
    
    size = length <= block->length ? length : block->length;
    memcpy(dst, block->data, size);
    
    buf = block->data;
    
    block->data = (char*)malloc(block->length -= size);
    memcpy(block->data, buf+size, block->length);
    
    free(buf);
    return size;
}

void http_free_buffer_blocks(http_buffer_block *block)
{
    if (block) {
        http_free_buffer_blocks(block->next);
        if (block->data)
            free(block->data);
        free(block);
    }
}

http_buffer_block *http_free_buffer_block(http_buffer_block *block)
{
    http_buffer_block *res = NULL;
    if (block) {
        res = block->next;
        if (block->data)
            free(block->data);
        free(block);
    }
    return res;
}

/* HTTP BUffer Functions */

http_buffer* http_make_buffer(int fd)
{
    http_buffer* res = (http_buffer*)malloc(sizeof(http_buffer));
    res->fd = fd;
    res->first = NULL;
    res->last = NULL;
    return res;
}

void http_free_buffer(http_buffer* buf)
{
    if (buf) {
        http_free_buffer_blocks(buf->first);
        free(buf);
    }
}

void http_buffer_append(http_buffer* buf, size_t length, const char* str)
{
    if (length && str) {
        http_buffer_block *block = http_make_buffer_block(length, str);
        
        if (! buf->first)
            buf->first = buf->last = block;
        else {
            buf->last->next = block;
            buf->last = buf->last->next;
        }
    }
}

#define BUFSIZE 1024
int http_buffer_recv(http_buffer* buf)
{
    if (buf->fd != -1) {
        char recv_buf[BUFSIZE];
        int length = recv(buf->fd, recv_buf, BUFSIZE, 0);
        write(0, recv_buf, length);
        if (length > 0) {
            http_buffer_append(buf, length, recv_buf);
        }
        return length;
    }
    return -1;
}

size_t http_buffer_length(http_buffer* buf)
{
    size_t length = 0;
    if (buf) {
        http_buffer_block * next = buf->first;
        while (next) {
            length += next->length;
            next = next->next;
        }
    }
    return length;
}

char *http_buffer_readln(http_buffer* buf)
{
    char *pos;
    size_t length = 0;
    if (!(buf->first) && (http_buffer_recv(buf) < 0)) {
        pos = (char*)malloc(1);
        pos[0] = 0;
        return pos;
    }
    http_buffer_block *block = buf->first;
    while (! (pos = strstr(block->data, HTTP_ENDL))) {
        length += block->length;
        if (!(block->next) && (http_buffer_recv(buf) < 0)) {
            pos = (char*)malloc(1);
            pos[0] = 0;
            return pos;
        }
        block = block->next;
    }
    length += (pos - block->data) + strlen(HTTP_ENDL);
    pos = http_buffer_read(buf, length);
    pos[length-1] = 0;
    pos[length-2] = 0;
    return pos;
}

char *http_buffer_read(http_buffer* buf, size_t length)
{
    char *res;
    size_t len = http_buffer_length(buf);
    while (len < length) {
        int bytes = http_buffer_recv(buf);
        if (bytes < 0) {
            return NULL;
        }
        len += bytes;
    }
    res = (char*)malloc(length);
    len = 0;
    while (len < length) {
        http_buffer_block *first = buf->first;
        if (first->length <= (length-len)) {
            memcpy(res+len, first->data, first->length);
            len += first->length;
            buf->first = http_free_buffer_block(first);
        } else {
            len += http_buffer_block_cat(first, res+len, length-len);
        }
    }
    return res;
}

int http_buffer_send(http_buffer *buf, int fd)
{
    buf->fd = fd;
    while (buf->first) {
        char *pos = buf->first->data;
        size_t length = buf->first->length;
        while (length) {
            int s = send(buf->fd, pos, length, 0);
            if (s < 0) { return -1; }
            pos += s;
            length -= s;
        }
        write(0, buf->first->data, buf->first->length);
        buf->first = http_free_buffer_block(buf->first);
    }
    buf->last = NULL;
    return 0;
}


http.c
#include <http.h>

#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>

http_request* http_make_request(const char *method, const char *resource,
    const http_headers *headers, size_t data_length, const char *data)
{
    http_request* res = (http_request*)malloc(sizeof(http_request));
    if (method) {
        res->method = (char*)malloc(strlen(method));
        strcpy(res->method, method);
    } else res->method = NULL;
    
    if (resource) {
        res->resource = (char*)malloc(strlen(resource));
        strcpy(res->resource, resource);
    } else res->resource = NULL;
    
    if (headers) {
        size_t i;
        res->headers = (http_headers*)malloc(sizeof(http_headers));
        for (i = 0; i < headers->length; ++i) {
            http_string_pair *pair = headers->hdrs[i];
            http_headers_push_back(res->headers, pair);
        }
    } else res->headers = NULL;
    
    res->data_length = data_length;
    if (res->data_length) {
        res->data = (char*)malloc(data_length);
        memcpy(res->data, data, data_length);
    } else res->data = NULL;
    return res;
}

void http_free_request(http_request* request) {
    if (request) {
        if (request->method)
            free(request->method);

        if (request->resource)
            free(request->resource);

        if (request->headers)
            http_free_headers(request->headers);
        
        if (request->data)
            free(request->data);

        free(request);
    }
}

http_request *http_parse_request(http_buffer* request)
{
    char *line, buf1[100], buf2[1024];
    http_request *res = (http_request *)malloc(sizeof(http_request));

    line = http_buffer_readln(request);
    sscanf(line, "%s%s", buf1, buf2);
    free(line);

    res->method = (char*)malloc(strlen(buf1)+1);
    memcpy(res->method, buf1, strlen(buf1)+1);
    
    res->resource = (char*)malloc(strlen(buf2)+1);
    memcpy(res->resource, buf2, strlen(buf2)+1);

    res->headers = http_make_headers(NULL);
    line = http_buffer_readln(request);
    while (strlen(line)) {
        if (isspace(line[0])) {
            char* pos = line;
            while (*pos && isspace(*pos)) pos++;
            if (res->headers->length) {
                http_string_pair *pair = res->headers->hdrs[res->headers->length-1];
                pair->value = (char*)realloc(pair->value,
                        strlen(pair->value) + strlen(pos) + 2);
                strcat(pair->value, " ");
                strcat(pair->value, pos);
            }
        } else {
            http_string_pair *pair;
            char* pos = strstr(line, HTTP_HEADER_DELIMITER);
            *pos = 0;
            pair = http_make_pair(line, pos+strlen(HTTP_HEADER_DELIMITER));
            http_headers_push_back(res->headers, pair);
            http_free_pair(pair);
        }
        free(line);
        line = http_buffer_readln(request);
    }
    free(line);
    
    const char *str = http_headers_get_value(res->headers, "Content-Length");
    if (str) {
        res->data_length = strtoul(str, NULL, 10);
        res->data = http_buffer_read(request, res->data_length);
    } else {
        res->data_length = 0;
        res->data = NULL;
    }

    return res;
}

http_response* http_make_response(int code, const http_headers *headers,
    size_t data_length, const char *data)
{
    http_response* res = (http_response*)malloc(sizeof(http_response));
    res->code = code;
    
    if (headers) {
        size_t i;
        res->headers = http_make_headers(NULL);
        for (i = 0; i < headers->length; ++i) {
            http_string_pair *pair = headers->hdrs[i];
            http_headers_push_back(res->headers, pair);
        }
    } else res->headers = NULL;
    
    res->data_length = data_length;
    if (res->data_length) {
        res->data = (char*)malloc(data_length);
        memcpy(res->data, data, data_length);
    } else res->data = NULL;

    return res;
}

void http_free_response(http_response* response)
{
    if (response) {
        if (response->headers)
            http_free_headers(response->headers);
        
        if (response->data)
            free(response->data);
        free(response);
    }
}

static const http_code_table code_table[] = {
    {200, "OK"},
    {201, "Created"},
    {202, "Accepted"},
    {204, "No content"},
    {301, "Moved Permanently"},
    {302, "Moved Temporarily"},
    {304, "Not Modified"},
    {400, "Bad Request"},
    {401, "Unauthorized"},
    {403, "Forbidden"},
    {404, "Not Found"},
    {500, "Internal Server Error"},
    {501, "Not Implemented"},
    {502, "Bad Gateway"},
    {503, "Service Unavailable"},
    {0, NULL}
};

const char *http_get_string_code (int code) {
    size_t i;
    for (i = 0; code_table[i].code; ++i) {
        if ( code_table[i].code == code )
            return code_table[i].str;
    }
    return NULL;
}

http_buffer *http_assemble_response(const http_response* response)
{
    http_buffer *res_buf;
    char buf[100], *headers;
    res_buf = http_make_buffer(-1);
    
    if (! http_headers_get_value(response->headers, "Content-Length")) {
        sprintf(buf, "%d", response->data_length);
        http_string_pair *pair = http_make_pair("Content-Length", buf);
        http_headers_push_back(response->headers, pair);
        http_free_pair(pair);
    }

    sprintf(buf, "HTTP/1.1 %d %s%s", response->code,
          http_get_string_code(response->code), HTTP_ENDL);
    http_buffer_append(res_buf, strlen(buf), buf);
    
    headers = http_headers_to_text(response->headers);
    http_buffer_append(res_buf, strlen(headers), headers);
    free(headers);
    
    http_buffer_append(res_buf, strlen(HTTP_ENDL), HTTP_ENDL);
    http_buffer_append(res_buf, response->data_length, response->data);
    return res_buf;
}

http_headers *http_make_headers(http_string_pair *pairs)
{
    http_headers *res = (http_headers *)malloc(sizeof(http_headers));
    res->length = 0;
    res->hdrs = NULL;

    if (pairs) {
        while (pairs->key) {
            http_headers_push_back(res, pairs);
            pairs++;
        }
    }

    return res;
}

int http_headers_push_back(http_headers *headers, const http_string_pair *pair)
{
    if (headers && pair) {
        headers->length++;
        headers->hdrs = (http_string_pair **)realloc(headers->hdrs,
                sizeof(http_string_pair *) * headers->length);
        headers->hdrs[headers->length-1] = http_make_pair(pair->key, pair->value);
        return headers->length;
    }
    return -1;
}

const char *http_headers_get_value(http_headers *headers, const char* key)
{
    size_t i;
    for (i = 0; i < headers->length; ++i) {
        if (! strcasecmp(headers->hdrs[i]->key, key))
            return headers->hdrs[i]->value;
    }
    return NULL;
}

char *http_headers_to_text(http_headers *headers)
{
    char *res;
    size_t i, length;
    for(i = 0; i < headers->length; ++i) {
        length += strlen(headers->hdrs[i]->key) + strlen(HTTP_HEADER_DELIMITER) + 
            strlen(headers->hdrs[i]->value) + strlen(HTTP_ENDL);
    }
    res = (char*)malloc(length+1);
    res[0] = 0;
    for(i = 0; i < headers->length; ++i) {
        strcat(res, headers->hdrs[i]->key);
        strcat(res, HTTP_HEADER_DELIMITER);
        strcat(res, headers->hdrs[i]->value);
        strcat(res, HTTP_ENDL);
    }
    return res;
}

void http_free_headers(http_headers *headers)
{
    size_t i;
    if (headers->length) {
        for (i = 0; i < headers->length; ++i) {
            http_free_pair(headers->hdrs[i]);
        }
        free(headers->hdrs);
    }
}

http_string_pair *http_make_pair(const char* key, const char* value)
{
    http_string_pair *res = (http_string_pair *)malloc(sizeof(http_string_pair));
    res->key = (char*)malloc(strlen(key)+1);
    memcpy(res->key, key, strlen(key)+1);
    res->value = (char*)malloc(strlen(value)+1);
    memcpy(res->value, value, strlen(value)+1);
    return res;
}

void http_free_pair(http_string_pair *pair)
{
    if (pair) {
        if (pair->key)
            free(pair->key);
        if (pair->value)
            free(pair->value);
        free(pair);
    }
}


http_server.c
/* 
 * File:   tcpserver.cpp
 * Author: yurik
 *
 * Created on 24 Сентябрь 2008 г., 0:29
 */

#include "http.h"


#include <tcp_server.h>

#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>

#include <http.h>

#define PORT    5555
#define MAXMSG  512

/*
    char buffer[MAXMSG];
    int nbytes;

    nbytes = read(fd, buffer, MAXMSG);
    if (nbytes < 0) {
        // Read error.
        perror("read");
        return (EXIT_FAILURE);
    } else if (nbytes == 0) {
        // End-of-file.
        printf("Server: client exiting\n");
        return -1;
    } else {
        // Data read.
        printf("Server: got message: `%s'\n", buffer);
        return 0;
    }
*/

http_string_pair pairs[] = {
    { "Server", "Yurror's multithread http server" },
    { "Content-Type", "text/html; charset=UTF-8" },
    { "Connection", "close" },
    { NULL, NULL }
};

http_response *http_process_request(http_request *request)
{
    char ans[] = "<html><head><title>Hello</title></head><body><p>Hello, world!</p></body></html>";
    http_headers *headers = http_make_headers(pairs);
    http_response *res = http_make_response(200, headers, strlen(ans), ans);
    http_free_headers(headers);
    return res;
}

int http_client_handler(int fd)
{
    int res;
    http_buffer *buffer = http_make_buffer(fd);
    http_request *request = http_parse_request(buffer);
    http_free_buffer(buffer);
    
    http_response *response = http_process_request(request);
    http_free_request(request);
    
    buffer = http_assemble_response(response);
    http_free_response(response);
    
    res = http_buffer_send(buffer, fd);
    http_free_buffer(buffer);
    return res;
}

int main(int argc, char** argv)
{
    return tcp_server_start(PORT, http_client_handler);
}


tcp_server.c
#include <tcp_server.h>

#include <arpa/inet.h>
#include <netdb.h>

#include <pthread.h>

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>

void *process_client(void *ptr)
{
    tcp_server_client *client = (tcp_server_client *)ptr;
/*
    printf ("Server: connect from host %s, port %d.\n",
        inet_ntoa(client->clientname.sin_addr),
            ntohs(client->clientname.sin_port)
    );
*/
    client->handler(client->fd);
    
    shutdown(client->fd, SHUT_RDWR);
    close(client->fd);
    free(client);
    pthread_exit(0);
}

int tcp_server_start(int port, tcp_server_handler handler)
{
    /* Create the socket and set it up to accept connections. */
    int sock;
    struct sockaddr_in name;

    /* Create the socket. */
    sock = socket(PF_INET, SOCK_STREAM, 0);
    if (sock < 0) {
        perror("socket");
        return (EXIT_FAILURE);
    }

    /* Give the socket a name. */
    name.sin_family = AF_INET;
    name.sin_port = htons(port);
    name.sin_addr.s_addr = htonl(INADDR_ANY);
    if (bind(sock, (struct sockaddr *) & name, sizeof (name)) < 0) {
        perror("bind");
        return (EXIT_FAILURE);
    }

    if (listen(sock, 1) < 0) {
        perror("listen");
        return (EXIT_FAILURE);
    }

    while (1) {
        pthread_t thread;
        tcp_server_client *client =
                (tcp_server_client *)malloc(sizeof(tcp_server_client));

        client->size = sizeof (client->clientname);
        client->handler = handler;
        client->fd = accept(sock, (struct sockaddr *) &(client->clientname),
                &(client->size));

        if (client->fd < 0) {
            perror ("accept"); free(client); continue;
        }
        
        pthread_create(&thread, NULL, &process_client, (void *)client);
    }
}


http_buffer.h
/* 
 * File:   http_buffer.h
 * Author: yurik
 *
 * Created on 27 Сентябрь 2008 г., 0:21
 */

#ifndef _HTTP_BUFFER_H
#define    _HTTP_BUFFER_H

#ifdef    __cplusplus
extern "C" {
#endif
    
#include <sys/types.h>

typedef struct _http_buffer_block {
    size_t length;
    char *data;
    struct _http_buffer_block *next;
} http_buffer_block;

http_buffer_block *http_make_buffer_block(size_t length, const char *data);
http_buffer_block *http_free_buffer_block(http_buffer_block *block);
void http_free_buffer_blocks(http_buffer_block *block);

typedef struct {
    int fd;
    http_buffer_block *first;
    http_buffer_block *last;
} http_buffer;

#define HTTP_ENDL "\r\n"

http_buffer* http_make_buffer(int fd);
void http_free_buffer(http_buffer* buf);

size_t http_buffer_length(http_buffer* buf);
int http_buffer_recv(http_buffer* buf);

void http_buffer_append(http_buffer* buf, size_t length, const char* str);
char *http_buffer_readln(http_buffer* buf);
char *http_buffer_read(http_buffer* buf, size_t length);
int http_buffer_send(http_buffer *buf, int fd);

#ifdef    __cplusplus
}
#endif

#endif    /* _HTTP_BUFFER_H */


http.h
/* 
 * File:   http.h
 * Author: yurik
 *
 * Created on 26 Сентябрь 2008 г., 23:16
 */

#ifndef _HTTP_H
#define    _HTTP_H

#ifdef    __cplusplus
extern "C" {
#endif

#include <http_buffer.h>
    
typedef struct {
    char *key;
    char *value;
} http_string_pair;

typedef struct {
    size_t length;
    http_string_pair **hdrs;
} http_headers;

typedef struct {
    char *method;
    char *resource;
    http_headers *headers;
    size_t data_length;
    char *data;
} http_request;

typedef struct {
    int code;
    http_headers *headers;
    size_t data_length;
    char *data;
} http_response;

typedef struct {
    int code;
    char * str;
} http_code_table;

#define HTTP_HEADER_DELIMITER ": "

http_request* http_make_request(
        const char *method,
        const char *resource,
        const http_headers *headers,
        size_t data_length,
        const char *data
    );

void http_free_request(http_request* request);

http_request* http_parse_request(http_buffer* request);

http_response* http_make_response(
        int code,
        const http_headers *headers,
        size_t data_length,
        const char *data
    );

void http_free_response(http_response* response);

http_buffer *http_assemble_response(const http_response* response);

http_headers* http_make_headers(http_string_pair *pairs);
char *http_headers_to_text(http_headers *headers);
int http_headers_push_back(http_headers *headers, const http_string_pair *pair);
const char *http_headers_get_value(http_headers *headers, const char* key);
void http_free_headers(http_headers *headers);

http_string_pair* http_make_pair(const char* key, const char* value);
void http_free_pair(http_string_pair *pair);

#ifdef    __cplusplus
}
#endif

#endif    /* _HTTP_H */


tcp_server.h
/* 
 * File:   tcp_server.h
 * Author: yurik
 *
 * Created on September 27, 2008, 4:06 PM
 */

#ifndef _TCP_SERVER_H
#define    _TCP_SERVER_H

#ifdef    __cplusplus
extern "C" {
#endif

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>

typedef int (*tcp_server_handler)(int);

typedef struct {
    int fd;
    tcp_server_handler handler;
    struct sockaddr_in clientname;
    socklen_t size;
} tcp_server_client;

int tcp_server_start(int port, tcp_server_handler handler);

#ifdef    __cplusplus
}
#endif

#endif    /* _TCP_SERVER_H */
Re[29]: C++ listen tcp socket
От: niXman Ниоткуда https://github.com/niXman
Дата: 13.10.11 08:17
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Как ни прискорбно — но с boost у меня тоже не срослось.

это как?
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Re[30]: C++ listen tcp socket
От: Handler Украина  
Дата: 13.10.11 09:36
Оценка:
Взял первый же пример из boost.asio — date_time, который посылает клиенту ответ. Так вот, я не смог прочитать от клиента сообщение.
Однако, это не заставило меня отказаться от boost вообще — только сейчас мне важнее разобраться с сокетами и потоками:
Первым делом — самолеты, ну а девушки — потом...
Whoa...I did a 'zcat /vmlinuz > /dev/audio' and I think I heard God...
Re[31]: C++ listen tcp socket
От: niXman Ниоткуда https://github.com/niXman
Дата: 13.10.11 09:40
Оценка:
Здравствуйте, Handler, Вы писали:

H>не смог прочитать от клиента сообщение.

там ведь пара: клиент и сервер. примеры все рабочие. так что, этого не может быть.
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Re[31]: C++ listen tcp socket
От: yurror Россия  
Дата: 13.10.11 10:19
Оценка:
Здравствуйте, Handler, Вы писали:

H>Взял первый же пример из boost.asio — date_time, который посылает клиенту ответ. Так вот, я не смог прочитать от клиента сообщение.

H>Однако, это не заставило меня отказаться от boost вообще — только сейчас мне важнее разобраться с сокетами и потоками:
H>Первым делом — самолеты, ну а девушки — потом...
Есть не только date_time. Есть примеры http-серверов.
Re[32]: C++ listen tcp socket
От: Handler Украина  
Дата: 17.10.11 11:02
Оценка:
Теперь встал еще один вопрос: Как отправить заголовок браузеру? Т.е.:
в 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
Пишу:
string str = "<html>...</html>";
string reply = "Accept-Charset: cp-1251"; //string reply = "Content-Type: text/html; charset=cp-1251"; 
reply+= "\r\n\r\n"; // end of header
reply+= str;

Ни один из этих вариантов браузер не считает за заголовки и выводит их в основное тело документа.
Как правильно и какие заголовки посылать браузеру?
Whoa...I did a 'zcat /vmlinuz > /dev/audio' and I think I heard God...
Re[34]: C++ listen tcp socket
От: Handler Украина  
Дата: 18.10.11 06:54
Оценка:
O>А где статусная строка (HTTP/1.1 200 OK) ?

H>>
H>>string str = "<html><head><meta http-equiv="content-type" content="text/html; charset=windows-1251"></head>...</html>";
H>>string reply = "";
reply+= "HTTP/1.1 200 OK\r\n";
reply+= "Content-length: "+str.length();
H>>reply+= "\r\n\r\n"; // end of header
H>>reply+= str;
H>>


Все равно не видит кодировку.

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...
Re[35]: C++ listen tcp socket
От: okman Беларусь https://searchinform.ru/
Дата: 18.10.11 07:13
Оценка:
Здравствуйте, Handler, Вы писали:

O>>А где статусная строка (HTTP/1.1 200 OK) ?


H>>>
H>>>string str = "<html><head><meta http-equiv="content-type" content="text/html; charset=windows-1251"></head>...</html>";
H>>>string reply = "";
H>reply+= "HTTP/1.1 200 OK\r\n";
H>reply+= "Content-length: "+str.length();
H>>>reply+= "\r\n\r\n"; // end of header
H>>>reply+= str;
H>>>


H>Все равно не видит кодировку.


Тут не хватает заголовка 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

А тут не хватает заголовка Accept-Charset.
Re[36]: C++ listen tcp socket
От: Handler Украина  
Дата: 18.10.11 11:30
Оценка:
Здравствуйте, okman, Вы писали:

H>>>>
H>>>>string str = "<html><head><meta http-equiv="content-type" content="text/html; charset=windows-1251"></head>...</html>";
H>>>>string reply = "";
H>>reply+= "HTTP/1.1 200 OK\r\n";
H>>reply+= "Content-length: "+str.length();
H>>>>reply+= "\r\n\r\n"; // end of header
H>>>>reply+= str;
H>>>>


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...
Re[37]: C++ listen tcp socket
От: okman Беларусь https://searchinform.ru/
Дата: 18.10.11 13:38
Оценка:
Здравствуйте, 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).
Re: C++ listen tcp socket
От: okman Беларусь https://searchinform.ru/
Дата: 18.10.11 14:03
Оценка:
Здравствуйте, Handler.

Из самого первого сообщения темы:

H>Создать приложение демон-процесс, слушающий и обрабатывающий запросы к TCP порту основанные на HTTP, выдающий в результате обработки запроса HTML-контент взятый из базы данных mysql, выполняющий перекодирование выдаваемого контента в желаемую/затребованную кодировку, которая устанавливается либо в самом запросе, либо в настройках его инициализационных параметров.


Для перекодирования текстового содержимого нужно использовать сторонние библиотеки.
Например, iconv. Лично я предпочитаю библиотеку ICU.

Логика работы веб-сервера тогда будет примерно следующей:
Принимаем HTTP-запрос, вытаскиваем из заголовка "Accept-Charset" кодировку (или берем ее
из настроек нашего веб-сервера), затем добываем HTML-контент из базы данных, перегоняем
его в нужную кодировку, после чего формируем заголовки ответа, не забыв про Content-Type и
charset, и в полученном виде отдаем клиенту.
Re[2]: C++ listen tcp socket
От: Handler Украина  
Дата: 19.10.11 09:05
Оценка:
Из Ваших двух сообщений узнал больше, чем за все время разбора данной задачи — большое Вам спасибо.
Whoa...I did a 'zcat /vmlinuz > /dev/audio' and I think I heard God...
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.