| Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
| Форум программистов > C/C++: Программирование под Unix/Linux > Как узнать что сокет продконнекчен ? |
| Автор: fray 13.12.2007, 20:03 |
| Просто я функцией select проверяю сокеты(не блокирующиеся), она выдает мне спиосок сокетов коннет которых с сервером уже пропал, а как сделать что бы коннект не пропадал c http-сервером(при условии что http -сервер это разрешает) ? |
| Автор: MAKCim 13.12.2007, 21:50 |
| какая ОС? |
| Автор: fray 14.12.2007, 01:28 | ||
линукс, ну в крайнем случае сигвин. |
| Автор: GrayCardinal 14.12.2007, 12:12 |
| getpeername (если память мне не изменяет) - выдаст адрес "другой стороны" подключенного сокета... возможно, вам это надо |
| Автор: xvr 14.12.2007, 16:08 | ||
Дурацкий вопрос - а ты http серверу сказал, что не надо закрывать http соединение после сеанса обмена ? |
| Автор: fray 14.12.2007, 18:35 | ||||||||||
ну я делаю так создаю сокет делаю не блокирующим конекчу его, потом проверяю select()ом можно ли в него писать или нет, если да то пишу, далее тем же select()ьом проверяю можно ли из него читать если да то читаю, на один http запрос (GET / HTTP/1.1\r\nHost: %s\r\nConnection: Close\r\n\r\n", hostname) этого хватает, потом как я пинимаю сервер зкрывает соединение на другом конце, то есть connect() пропадает, то есть как мне казалось select() должен мне тперь сказать что типа нельзя болье писать в этот сокет, а он говорит что можно. Добавлено @ 18:38
да вопрос действительно дурацкий, но иногда приходится и такие вопросы задавать, дело в том что тут два вопроса в одном, почему коннект пропадает и как узнать что коннект еще есть , да вроде ставил keep-alive в http запросе результат тот же. Сейчас попробовал sprintf(request, "GET / HTTP/1.1\r\nHost: %s\r\nConnection: Keep-Alive\r\n\r\n", hostname);sprintf(request, "GET / HTTP/1.1\r\nHost: %s\r\nConnection: Keep-Alive\r\n\r\n", hostname); и так тоже sprintf(request, "GET / HTTP/1.1\r\nHost: %s\r\n\r\n", hostname); результак как и с Connection: Close, в настройках апача стоит Кеер-Alive on Добавлено @ 18:41
ок проверим |
| Автор: Олег2005 14.12.2007, 19:20 |
Нормальный сервер не может держать соединение открытым бесконечно - и обычно в Апачах он держит его 10 сек (это настраивается в конфиге) - иначе таких соединений висящих будет сотни тысяч. Для имитации открытого соединение со стороны клиента достаточно сокет создать с флагом TCP_KEEPALIVE и установить опцию сокета SO_KEEPALIVE |
| Автор: fray 15.12.2007, 00:18 | ||||
надеюсь этого будет достаточно
только вот ругается на TCP_KEEPALIVE в каком хедере определен ? |
| Автор: xvr 15.12.2007, 11:15 | ||||||||||||||||||
Ты сам его попросил закрыть соединение (Connection: Close), что он и сделал
Это тебе скажет write, и то не сразу.
Для http 1.1 keep-alive включен по умолчанию, если не стоит Connection: Close
Это странно, должно работать
Статус подключения он не выдаст :( |
| Автор: fray 15.12.2007, 20:35 | ||||||||
Да это тоже работает но не так как надо всмысле посылаю запрос получаю первый ответ а потом висим опрашивая дескрипторы poll(), апач в ответе отвечает keep-alive, timeout 10, было так
Короче нужен мне был клиент качающий в несколько потоков, вернулся назад к закрывающемуся соединению. хотя конечно хотелось бы добиться чтобы соединение не разрывалось как можно дольше, может апач не хочет чтобы я ему слал одинаковые запросы GET / к начальной странице.
|
| Автор: Олег2005 15.12.2007, 20:46 |
| Надо иметь в виду, что KEEPALIVE протокола HTTP не имеет ничего общего с TCP_KEEPALIVE |
| Автор: fray 15.12.2007, 22:17 | ||||
если под TCP_KEEPALIVE вы понимаете это, то это я включал
и если TCP_KEEPALIVE никак не связано с KEEPALIVE протокола HTTP, то чтобы не делать такой запрос GET / HTTP/1.1\r\nHost: %s\r\nConnection: Close\r\n\r\n" и по новой создавать каждый раз socket() и connect(). |
| Автор: Олег2005 15.12.2007, 23:07 | ||
Cервер HTTP/1.1 - даже если ему ничего типа Keepalive не слать - будет несколько секунд держать соединение после отсылки ответа клиенту Поэтому я лично не очень понимаю суть поставленной вами проблем - открыли сокет, сконнектились, послали запрос и вышли на recv() и ждем ответа сервера. Быстренько его парсим - и если нужны картинки, выдаем запрос по тому же сокету - но уже на картиночный файл - это я в качестве идеологии привожу - и сервер обязан держать соединение открытым мин 10 секунд. |
| Автор: fray 16.12.2007, 00:16 | ||
может я что-то не пойму конечно, но я делаю так sd=socket () // создал сокет O_NONBLOCK // сделал не блокирующим setsockopt(sd,SO_KEEPALIVE) // делаю его кипэлайф connect (sd); // конекчу скармливаю sd poll()'y while ( poll() ) // опрашитваю пулл { если Можно читать данные то read() если Можно писать данные то write() } казалось бы по вашим словам если коннект держится в течении 10 секунд должен идти беспрерывный обмен данными но на деле получается что я шлю запрос и получаю один ответ, коннек держится 10 сек а потом poll отвечает мне что произошла ошибка. Поэтому для каждого запроса я создаю сокет и коннект, а это как-то не экономично. |
| Автор: Олег2005 16.12.2007, 01:21 | ||||
Что же вы шлете в этом самом первом write()? Запрос GET? Ок, вы пишите - ответ получаете Какой именно - те что отвечает сервер, 200 ОК? Данные какие шлет? Если пришло все, что вы хотели - то ясное дело что вы на сервер ничего не посылаете А если пришел ответ - то надо что-то сразу слать Кстати какой интервал вы ставите в TCP_KEEPALIVE? Наверно с логикой запросов-ответов (те верхним протоколом) у вас что-то не так
Ну а ошибка то какая? что лежит в errno? |
| Автор: xvr 17.12.2007, 13:04 | ||||
Все правильно - послали один запрос, получили один ответ - все. Шлите другой запрос, сам по себе http сервер ничего лить не будет, keep alive тут ни при чем |
| Автор: fray 17.12.2007, 16:29 | ||||||||||
В первом запросе я шлю sprintf(request, "GET / HTTP/1.1\r\nHost: %s\r\n\r\n", hostname); ответ:
вот так я выставляю TCP_KEEPALIVE, if(setsockopt(sd, SOL_SOCKET, SO_KEEPALIVE, (char*)&len, sizeof(len)) == -1){ perror("tcp_listen: setsockopt(SO_KEEPALIVE) 1"); return 0; } время коннекта я понимаю должно в линуксе sysctl выставлятся(хотя можно через структуру tcp_kpalive, но в сигвине у меня такого нет), но даже так думаю время соединения должно быть больше секунды так что я бы успел получить хотя бы два ответа.
А что может быть не так ? в errno: 113 (connect abort) А вот если я шлю sprintf(request, "GET / HTTP/1.1\r\nHost: %s\r\nKeep-Alive: 300\r\nConnection: keep-alive\r\nReferer: http://%s/\r\n\r\n", hostname, hostname); то ответ получаю
А в Errno: errno: 119 (connection in progress) errno: 119 (connection in progress) errno: 113 (connect aborted) .............. Добавлено @ 16:42
Я так и делаю но чтобы мне послать следующий запрос мне приходится создавать connect, то есть получается коннкт для каждого запроса, моя проблема и заключается в том, можно ли удержать connect для посылки через него 2 или более запросов !!! Вот испытал на лунуксе, думал переводить неблокирующий режим в асинхронный если errno == EINPROGRESS, но получил еще более странный результат. при посыле вот этого получил
как понимать Cannot process request! server does not support the action requested by the browser, может что-то в апаче включить ? |
| Автор: fray 17.12.2007, 18:26 |
| настройки системы net.ipv4.tcp_keepalive_time = 7200 net.ipv4.tcp_keepalive_probes = 9 net.ipv4.tcp_keepalive_intvl = 75 |
| Автор: Олег2005 17.12.2007, 18:39 | ||
| Что это за хитрый файл? Content-Location: index.html.en - который лежит в каталоге Апачей? Поэтому Апачи отвечают что
Апач наверно незнаком с расширением .en? После чего, так как ошибка явная, он соединение наверно и закрывает- и вам приходится все по новой делать В общем при нормальной конфигурации Апачей и клиента все должно работать и без всяких TCP_Keepalive тд Надо точно формулировать запросы |
| Автор: fray 18.12.2007, 23:39 | ||
я заменил index.html.en на index.html, результат остался прежним. а что вы понимаете под этим, думаю с http-запросами все ок, просто видимо апач не терпит того что я шлю ему запросы хотя он еще не ответил на первый запрос, мне уже начинает казаться что послать два запроса в один коннект это невозможно |
| Автор: Олег2005 19.12.2007, 00:12 |
Опять пишет что метод не поддерживается в первом ответе? Можете опять распечаточку респонса привести? |
| Автор: onsql 19.12.2007, 00:41 |
| Насколько мне известно, по закрытии соединения другой стороной в select будет постоянно возникать read event, а read() или recv() будут возвращать 0. |
| Автор: fray 19.12.2007, 02:27 | ||||
вот таким запросом запрашиваю главную страницу на localhost'e: sprintf(request, "GET / HTTP/1.1\r\nHost: %s\r\nKeep-Alive: 300\r\nUser-Agent: (X11; U; Linux i686; en-US; rv:1.8.1.6) Gecko/20070208 Firefox/2.0.0.6 \r\nAccept: text/plan;q=0.8,image/png,*/*;q=0.5\r\nConnection: keep-alive\r\nReferer: http://%s/\r\n\r\n", hostname, hostname); вот ответ: это соответсвено index.html
а дальше я cделал так что послал запрос если не получил на него ответ, но новый запрос не шлет даже если poll'er говорить что можно писать, send req: 1 // шлю первый запрос HTTP/1.1 200 OK Date: Tue, 18 Dec 2007 23:20:26 GMT Server: Apache/2.2.6 (Mandriva Linux/PREFORK-8mdv2008.0) Last-Modified: Fri, 07 Sep 2007 20:47:11 GMT ETag: "ef786-2c-be3491c0" Accept-Ranges: bytes Content-Length: 44 Keep-Alive: timeout=5, max=100 Connection: Keep-Alive Content-Type: text/html <html><body><h1>It works!</h1></body></html> send req: 2 // шлю второй запрос ответа не получаю тут прога висит в ожидании ответа на второй запрос через тот же коннкт. [user@localhost 2]$ netstat -t tcp 0 0 localhost:46809 localhost:http CLOSE_WAIT и соединение весит в таком состояние бесконечно долго. Сам сервак (как бы это сказать) до конца соединение не закрывает. |
| Автор: Олег2005 19.12.2007, 11:46 |
Теперь вернемся к первой цитате. Вы используете select() на клиенте в цикле? Если да, то тогда все понятно. Его в цикле использовать можно, но только специальным образом - иначе все сбрасывается и больше на сетевые события он не реагирует - те после первого запроса все замирает |
| Автор: fray 19.12.2007, 13:58 | ||||
Да, но только не select()'том, а его собратом poll()'ом, но думаю тут нет большой разницы.
Объясните плизз, а то я не очень понял почему. |
| Автор: Олег2005 19.12.2007, 16:28 | ||
Не могу сказать про poll() - хотя вполне вероятно
Те если перед этим вы делали все FD_SET - те заносили в нужный набор - и по этому признаку не сработало - а сработало по другому - то все наборы после select() обнуляются и для исполнения select() в цикле надо делать все FD_ SET заново |
| Автор: fray 21.12.2007, 17:04 | ||||||||
это все конечно круто
Программа получает только ответ от первого запроса. А от второго ничего. хотя эти отлично работаетают когда я руками их копирую.
|
| Автор: onsql 21.12.2007, 17:28 | ||
| А точно происходит второй write? Попробуй поставить перед после него отладочную печать. Также надо бы попечатать возвращаемые значения write (Никто не гарантирует что write запишет столько байт, сколько ты попросил, сколько записано - он возвращает) Вообще говоря, поскольку сокет у тебя блокируемый и следоваетльно, ф-ии read и write не возвращают ошибок EAGAIN или EWOULDBLOCK то вот это выражение
означает: "читать пока не произойдёт disconnect" |
| Автор: Олег2005 21.12.2007, 17:58 | ||||
| onsql прав, и ему большой плюс за это Этот фрагмент:
предполагает продолжение операции чтения до тех пор, пока не выскочит ошибка (-1 ) или не прийдет признак FIN n=0 - а это точно, что соединение закрыто!!! Почему бы просто не написать
и слать следующий запрос по еще открытому сокету!!!! |
| Автор: fray 21.12.2007, 20:07 | ||
да спасибо, за разъяснение
вот так работет как надо |