Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > 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
Цитата(MAKCim @ 13.12.2007,  21:50)
какая ОС?

линукс, ну в крайнем случае сигвин.

Автор: MAKCim 14.12.2007, 10:32
Цитата(fray @  13.12.2007,  20:03 Найти цитируемый пост)
она выдает мне спиосок сокетов коннет которых с сервером уже пропал, а как сделать что бы коннект не пропадал c http-сервером

вообще select() проверяет возможность неблокирующего чтения/записи с использованием дескрипторов
при чем здесь коннект?

Автор: GrayCardinal 14.12.2007, 12:12
getpeername (если память мне не изменяет) - выдаст адрес "другой стороны" подключенного сокета... возможно, вам это надо  smile 

Автор: xvr 14.12.2007, 16:08
Цитата(fray @ 13.12.2007,  20:03)
Просто я функцией select проверяю сокеты(не блокирующиеся), она выдает мне спиосок сокетов коннет которых с сервером уже пропал, а как сделать что бы коннект не пропадал c http-сервером(при условии что http -сервер это разрешает) ?

Дурацкий вопрос - а ты http серверу сказал, что не надо закрывать http соединение после сеанса обмена ?

Автор: fray 14.12.2007, 18:35
Цитата(MAKCim @ 14.12.2007,  10:32)
Цитата(fray @  13.12.2007,  20:03 Найти цитируемый пост)
она выдает мне спиосок сокетов коннет которых с сервером уже пропал, а как сделать что бы коннект не пропадал c http-сервером

вообще select() проверяет возможность неблокирующего чтения/записи с использованием дескрипторов
при чем здесь коннект?

ну я делаю так создаю сокет делаю не блокирующим конекчу его, потом проверяю select()ом можно ли в него писать или нет, если да то пишу, далее тем же select()ьом проверяю можно ли из него читать если да то читаю, на один http запрос (GET / HTTP/1.1\r\nHost: %s\r\nConnection: Close\r\n\r\n", hostname) этого хватает, потом как я пинимаю сервер зкрывает соединение на другом конце, то есть connect() пропадает, то есть как мне казалось select() должен мне тперь сказать что типа нельзя болье писать в этот сокет, а он говорит что можно.

Добавлено @ 18:38
Цитата(xvr @ 14.12.2007,  16:08)
Цитата(fray @ 13.12.2007,  20:03)
Просто я функцией select проверяю сокеты(не блокирующиеся), она выдает мне спиосок сокетов коннет которых с сервером уже пропал, а как сделать что бы коннект не пропадал c http-сервером(при условии что http -сервер это разрешает) ?

Дурацкий вопрос - а ты http серверу сказал, что не надо закрывать http соединение после сеанса обмена ?

да вопрос действительно дурацкий, но иногда приходится и такие вопросы задавать, дело в том что тут два вопроса в одном, почему коннект пропадает  и как узнать что коннект еще есть , да вроде ставил 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
Цитата(GrayCardinal @ 14.12.2007,  12:12)
getpeername (если память мне не изменяет) - выдаст адрес "другой стороны" подключенного сокета... возможно, вам это надо  smile

ок проверим

Автор: Олег2005 14.12.2007, 19:20
Цитата(fray @  14.12.2007,  18:35 Найти цитируемый пост)
в настройках апача стоит Кеер-Alive on 

Нормальный сервер не может держать соединение открытым бесконечно - и обычно в Апачах он держит его 10 сек (это настраивается в конфиге) - иначе таких соединений висящих будет сотни тысяч.
Для имитации открытого соединение со стороны клиента достаточно сокет создать с флагом TCP_KEEPALIVE и установить опцию сокета SO_KEEPALIVE 

Автор: fray 15.12.2007, 00:18
Цитата(Олег2005 @ 14.12.2007,  19:20)
Цитата(fray @  14.12.2007,  18:35 Найти цитируемый пост)
в настройках апача стоит Кеер-Alive on 

Нормальный сервер не может держать соединение открытым бесконечно - и обычно в Апачах он держит его 10 сек (это настраивается в конфиге) - иначе таких соединений висящих будет сотни тысяч.
Для имитации открытого соединение со стороны клиента достаточно сокет создать с флагом TCP_KEEPALIVE и установить опцию сокета SO_KEEPALIVE

надеюсь этого будет достаточно smile.
Код

        int on = 1;
        setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on) ); 
        setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPALIVE, &on, sizeof(on));

только вот ругается на TCP_KEEPALIVE в каком хедере определен ?

Автор: xvr 15.12.2007, 11:15
Цитата(fray @ 14.12.2007,  18:35)
Цитата(MAKCim @ 14.12.2007,  10:32)
Цитата(fray @  13.12.2007,  20:03 Найти цитируемый пост)
она выдает мне спиосок сокетов коннет которых с сервером уже пропал, а как сделать что бы коннект не пропадал c http-сервером

вообще select() проверяет возможность неблокирующего чтения/записи с использованием дескрипторов
при чем здесь коннект?

ну я делаю так создаю сокет делаю не блокирующим конекчу его, потом проверяю select()ом можно ли в него писать или нет, если да то пишу, далее тем же select()ьом проверяю можно ли из него читать если да то читаю, на один http запрос (GET / HTTP/1.1\r\nHost: %s\r\nConnection: Close\r\n\r\n", hostname) этого хватает, 

Ты сам его попросил закрыть соединение (Connection: Close), что он и сделал

Цитата

потом как я пинимаю сервер зкрывает соединение на другом конце, то есть connect() пропадает, то есть как мне казалось select() должен мне тперь сказать что типа нельзя болье писать в этот сокет, а он говорит что можно.

Это тебе скажет write, и то не сразу.

Цитата

Цитата

Дурацкий вопрос - а ты http серверу сказал, что не надо закрывать http соединение после сеанса обмена ?

да вопрос действительно дурацкий, но иногда приходится и такие вопросы задавать, дело в том что тут два вопроса в одном, почему коннект пропадает  и как узнать что коннект еще есть , да вроде ставил keep-alive в http запросе результат тот же. 

Для http 1.1 keep-alive включен по умолчанию, если не стоит Connection: Close

Цитата

Сейчас попробовал 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
Цитата(GrayCardinal @ 14.12.2007,  12:12)
getpeername (если память мне не изменяет) - выдаст адрес "другой стороны" подключенного сокета... возможно, вам это надо  smile

ок проверим

Статус подключения он не выдаст :(

Автор: fray 15.12.2007, 20:35
Цитата(xvr @  15.12.2007,  11:15 Найти цитируемый пост)
Для http 1.1 keep-alive включен по умолчанию, если не стоит Connection: Close
Цитата
Сейчас попробовал 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 

Это странно, должно работать


Да это тоже работает но не так как надо всмысле посылаю запрос получаю первый ответ а потом висим опрашивая дескрипторы poll(), апач в ответе отвечает keep-alive, timeout 10, было так 
Код

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); 
 +        
Код

int on = 1;
        setsockopt(sd, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on)); 
        setsockopt(sd, IPPROTO_TCP, SO_KEEPALIVE, &on, sizeof(on)); // хотя не знаю правильно ли это :)

Короче нужен мне был клиент качающий в несколько потоков, вернулся назад к закрывающемуся соединению. хотя конечно хотелось бы добиться чтобы соединение не разрывалось как можно дольше, может апач не хочет чтобы я ему слал одинаковые запросы  GET / к начальной странице.
Код

sprintf(request, "GET / HTTP/1.1\r\nHost: %s\r\nConnection: Close\r\n\r\n", hostname);


Автор: Олег2005 15.12.2007, 20:46
Надо иметь в виду, что KEEPALIVE протокола HTTP не имеет ничего общего с 
TCP_KEEPALIVE 

Автор: fray 15.12.2007, 22:17
Цитата(Олег2005 @ 15.12.2007,  20:46)
Надо иметь в виду, что KEEPALIVE протокола HTTP не имеет ничего общего с 
TCP_KEEPALIVE

если под TCP_KEEPALIVE вы понимаете это, то это я включал
Код

#ifdef TCP_KEEPALIVE
  len = 0;
  if(setsockopt(*newSocket, SOL_SOCKET, SO_KEEPALIVE, (char*)&len, 
        sizeof(len)) == -1){
     perror("tcp_listen: setsockopt(SO_KEEPALIVE)"); return FALSE;
  }
#endif

и если  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
Цитата

Connection      
 Постоянные соединения для сообщений HTTP/1.1 работают по умолчанию; для декларации непостоянства соединения вводится ключевое слово close. Ниже описана оригинальная форма постоянных соединений для HTTP/1.0. Когда HTTP клиент соединяется с исходным сервером, он может послать лексему соединения Keep-Alive в дополнение к лексеме соединения Persist: 
Connection: Keep-Alive.
Клиент предлагает не закрывать TCP-соединение после обработки запроса, с тем чтобы это соединение могло быть использовано для последующих запросов и ответов на них. Если новые запросы не последовали в течение некоторого времени (несколько секунд), сервер закрывает соединение. Значение заголовка "Connection: close" указывает на то, что соединение будет закрыто после обработки данного запроса. 

Cервер  HTTP/1.1 - даже если ему ничего типа Keepalive не слать - будет несколько секунд держать соединение после отсылки ответа  клиенту
Поэтому я лично не очень понимаю суть поставленной вами проблем - открыли сокет, сконнектились, послали запрос и вышли на recv() и ждем ответа сервера. Быстренько его парсим - и если нужны картинки, выдаем запрос по тому же сокету - но уже на картиночный файл - это я в качестве идеологии привожу - и сервер обязан держать соединение открытым мин 10 секунд.

Автор: fray 16.12.2007, 00:16
Цитата(Олег2005 @  15.12.2007,  23:07 Найти цитируемый пост)
я лично не очень понимаю суть поставленной вами проблем - открыли сокет, сконнектились, послали запрос и вышли на recv() и ждем ответа сервера. Быстренько его парсим - и если нужны картинки, выдаем запрос по тому же сокету - но уже на картиночный файл - это я в качестве идеологии привожу - и сервер обязан держать соединение открытым мин 10 секунд.

может я что-то не пойму конечно, но я делаю так 
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
Цитата(fray @  16.12.2007,  00:16 Найти цитируемый пост)
казалось бы по вашим словам если коннект держится в течении 10 секунд должен идти беспрерывный обмен данными но на деле получается что я шлю запрос и получаю один ответ

Что же вы шлете в этом самом первом write()?
Запрос GET?
Ок, вы пишите - ответ получаете
Какой именно - те что отвечает сервер, 200 ОК?
Данные какие шлет?
Если пришло все, что вы хотели - то ясное дело что вы на сервер ничего не посылаете
А если пришел ответ - то надо что-то сразу слать
Кстати какой интервал вы ставите в TCP_KEEPALIVE?
Наверно с логикой запросов-ответов (те верхним протоколом) у вас что-то не так smile 

Цитата

, коннект держится 10 сек а потом poll отвечает мне что произошла ошибка. 

Ну а ошибка то какая? что лежит в errno?

Автор: xvr 17.12.2007, 13:04
Цитата(fray @ 15.12.2007,  20:35)
Цитата(xvr @  15.12.2007,  11:15 Найти цитируемый пост)
Для http 1.1 keep-alive включен по умолчанию, если не стоит Connection: Close
Цитата
Сейчас попробовал 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 

Это странно, должно работать


Да это тоже работает но не так как надо всмысле посылаю запрос получаю первый ответ а потом висим опрашивая дескрипторы poll(), апач в ответе отвечает keep-alive, timeout 10

Все правильно - послали один запрос, получили один ответ - все. Шлите другой запрос, сам по себе http сервер ничего лить не будет, keep alive тут ни при чем  smile 

Автор: fray 17.12.2007, 16:29
Цитата(Олег2005 @  16.12.2007,  01:21 Найти цитируемый пост)
Что же вы шлете в этом самом первом write()?

В первом запросе я шлю 
sprintf(request, "GET / HTTP/1.1\r\nHost: %s\r\n\r\n", hostname); 
ответ:
Код

HTTP/1.1 200 OK
Date: Mon, 17 Dec 2007 13:11:37 GMT
Server: Apache/2.0.59 (Win32)
Content-Location: index.html.en
Vary: negotiate,accept-language,accept-charset
TCN: choice
Last-Modified: Sun, 21 Nov 2004 05:35:22 GMT
ETag: "35a2d060-5d6-1b28fa80;35a2dac0-9dc-1b28fa80"
Accept-Ranges: bytes
Content-Length: 1494
Content-Type: text/html
Content-Language: en

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Test Page for Apache Installation</title>
</head>
<!-- Background white, links blue (unvisited), navy (visited), red
(active) -->
<body bgcolor="#FFFFFF" text="#000000" link="#0000FF"
vlink="#000080" alink="#FF0000">
<p>If you can see this, it means that the installation of the <a
href="http://www.apache.org/foundation/preFAQ.html">Apache web
server</a> software on this system was successful. You may now add
content to this directory and replace this p
age.</p>

<hr width="50%" size="8" />
<h2 align="center">Seeing this instead of the website you
expected?</h2>

<p>This page is here because the site administrator has changed the
configuration of this web server. Please <strong>contact the person
responsible for maintaining this server with questions.</strong>
The Apache Software Foundation, which wrote the web server software
this site administrator is using, has nothing to do with
maintaining this site and cannot help resolve configuration
issues.</p>

<hr width="50%" size="8" />
<p>The Apache <a href="manual/">documentation</a> has been included
with this distribution.</p>

<p>You are free to use the image below on an Apache-powered web
server. Thanks for using Apache!</p>

<div align="center"><img src="apache_pb.gif" alt="" /></div>
</body>
</html>

<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>501 Method Not Implemented</title>
</head><body>
<h1>Method Not Implemented</h1>
<p> to /index.html.en not suppo
rted.<br />
</p>
<hr>
<address>Apache/2.0.59 (Win32) Server at localhost Port 80</address>
</body></html>
Произошла ошибка : 1
errno: 113    Произошла ошибка : 1
errno: 113    Произошла ошибка : 1


Цитата(Олег2005 @  16.12.2007,  01:21 Найти цитируемый пост)
Кстати какой интервал вы ставите в TCP_KEEPALIVE?

вот так я выставляю 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, но в сигвине у меня такого нет), но даже так думаю время соединения должно быть больше секунды так что я бы успел получить хотя бы два ответа.



Цитата(Олег2005 @  16.12.2007,  01:21 Найти цитируемый пост)
Наверно с логикой запросов-ответов (те верхним протоколом) у вас что-то не так

А что может быть не так ?

Цитата(Олег2005 @  16.12.2007,  01:21 Найти цитируемый пост)
Ну а ошибка то какая? что лежит в errno? 

в 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);
то ответ получаю 
Код

HTTP/1.1 200 OK
Date: Mon, 17 Dec 2007 13:31:40 GMT
Server: Apache/2.0.59 (Win32)
Content-Location: index.html.en
Vary: negotiate,accept-language,accept-charset
TCN: choice
Last-Modified: Sun, 21 Nov 2004 05:35:22 GMT
ETag: "35a2d060-5d6-1b28fa80;35a2dac0-9dc-1b28fa80"
Accept-Ranges: bytes
Content-Length: 1494
Keep-Alive: timeout=15, max=100
Connection: Keep-Alive
Content-Type: text/html
Content-Language: en

А в Errno: 
errno: 119 (connection in progress)
errno: 119 (connection in progress)
errno: 113 (connect aborted)
..............

Добавлено @ 16:42
Цитата(xvr @  17.12.2007,  13:04 Найти цитируемый пост)
Все правильно - послали один запрос, получили один ответ - все. Шлите другой запрос, сам по себе http сервер ничего лить не будет, keep alive тут ни при чем  smile 

Я так и делаю но чтобы мне послать следующий запрос мне приходится создавать connect, то есть получается коннкт для каждого запроса, моя проблема и заключается в том, можно ли удержать connect для посылки через него 2 или более запросов !!!

Вот испытал на лунуксе, думал переводить неблокирующий режим в асинхронный если errno == EINPROGRESS, но получил еще более странный результат.
при посыле вот этого получил 

Код

HTTP/1.1 200 OK
Date: Mon, 17 Dec 2007 14:58:25 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
Content-Type: text/html

<html><body><h1>It works!</h1></body></html><?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<title>Cannot process request!</title>
<body>
<h1>Cannot process request!</h1>
<p>
    The server does not support the action requested by the browser.
</p>
<p>
If you think this is a server error, please co
ntact
the <a href="mailto:root@localhost">webmaster</a>.
</p>
<h2>Error 501</h2>
</body>
</html>


как понимать 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 - который лежит в каталоге Апачей?
Поэтому Апачи отвечают что
Цитата

<h1>Method Not Implemented</h1>
<p> to /index.html.en not supported.<br />

Апач наверно незнаком с расширением .en?
После чего, так как ошибка явная, он соединение наверно и закрывает- и вам приходится все по новой делать
В общем при нормальной конфигурации Апачей и клиента все должно работать и без всяких TCP_Keepalive  тд
Надо точно формулировать запросы

Автор: fray 18.12.2007, 23:39
Цитата(Олег2005 @  17.12.2007,  18:39 Найти цитируемый пост)
Что это за хитрый файл?
Content-Location: index.html.en - который лежит в каталоге Апачей?
Поэтому Апачи отвечают что

я заменил index.html.en на index.html, результат остался прежним. 

Цитата(Олег2005 @  17.12.2007,  18:39 Найти цитируемый пост)
Надо точно формулировать запросы 

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

Автор: Олег2005 19.12.2007, 00:12
Цитата(fray @  18.12.2007,  23:39 Найти цитируемый пост)
я заменил index.html.en на index.html, результат остался прежним. 

Опять пишет что метод не поддерживается в первом ответе?
Можете опять распечаточку респонса привести?

Автор: onsql 19.12.2007, 00:41
Насколько мне известно, по закрытии соединения другой стороной в select будет постоянно возникать read event, а read() или  recv() будут возвращать 0.

Автор: fray 19.12.2007, 02:27
Цитата(Олег2005 @  19.12.2007,  00:12 Найти цитируемый пост)
Опять пишет что метод не поддерживается в первом ответе?
Можете опять распечаточку респонса привести? 

вот таким запросом запрашиваю главную страницу на 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

Код

HTTP/1.1 200 OK 1
Date: Tue, 18 Dec 2007 23:09:53 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>


а дальше я 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
Цитата(fray @  13.12.2007,  20:03 Найти цитируемый пост)
Просто я функцией select проверяю сокеты(не блокирующиеся)

Теперь вернемся к первой цитате.
Вы используете select() на клиенте в цикле?
Если да, то тогда все понятно.
Его в цикле использовать можно, но только специальным образом - иначе все сбрасывается и больше на сетевые события он не реагирует - те после первого запроса все замирает

Автор: fray 19.12.2007, 13:58
Цитата(Олег2005 @  19.12.2007,  11:46 Найти цитируемый пост)
Теперь вернемся к первой цитате.
Вы используете select() на клиенте в цикле?

Да, но только не select()'том, а его собратом poll()'ом, но думаю тут нет большой разницы.

Цитата(Олег2005 @  19.12.2007,  11:46 Найти цитируемый пост)
Если да, то тогда все понятно.
Его в цикле использовать можно, но только специальным образом - иначе все сбрасывается и больше на сетевые события он не реагирует - те после первого запроса все замирает 

Объясните плизз, а то я не очень понял почему.

Автор: Олег2005 19.12.2007, 16:28
Не могу сказать про poll() - хотя вполне вероятно
Цитата

После своего завершения функция select() сбросит биты, указывающие на любой сокет, не готовый к определенной операции ввода-вывода.

Те если перед этим вы делали все FD_SET - те заносили в нужный набор - и по этому признаку не сработало - а сработало по другому - то все наборы после select() обнуляются и для исполнения select() в цикле надо делать все FD_ SET заново

Автор: fray 21.12.2007, 17:04
Цитата(Олег2005 @ 19.12.2007,  16:28)
Не могу сказать про poll() - хотя вполне вероятно
Цитата

После своего завершения функция select() сбросит биты, указывающие на любой сокет, не готовый к определенной операции ввода-вывода.

Те если перед этим вы делали все FD_SET - те заносили в нужный набор - и по этому признаку не сработало - а сработало по другому - то все наборы после select() обнуляются и для исполнения select() в цикле надо делать все FD_ SET заново

это все конечно круто smile, но я понял что у меня не работает даже так 

Код

int main(int argc,char* argv[]) {

        int k = 1;
        char tmp[1024]; // temporay array
        memset(tmp, 0, sizeof tmp);
        int  i, j=0, sd;
        struct sockaddr_in sock_name;
        struct hostent *hptr;

        char *hostname = "localhost"; // localhost
        int port =80;

        if (!(hptr = gethostbyname (hostname))) {
                perror("cant get host");
        }

        memcpy (&sock_name.sin_addr, hptr->h_addr, hptr->h_length);
        sock_name.sin_family = AF_INET;
        sock_name.sin_port = htons (port);
        char request[100], request2[100];
        memset(request, 0, 100);
        memset(request2, 0, 100);
        sprintf(request, "GET / HTTP/1.1\r\nConnection: keep-alive\r\nHost: %s\r\n\r\n", hostname);
        sprintf(request2, "GET /cgi-bin/test.cgi HTTP/1.1\r\nConnection: keep-alive\r\nHost: %s\r\n\r\n", hostname);

        if ( (sd = socket (AF_INET, SOCK_STREAM, 0)) ==-1 ){
                perror("socket");
        }

        int len = 1;
        if(setsockopt(sd, SOL_SOCKET, SO_KEEPALIVE, (char*)&len, sizeof(len)) == -1){
                perror("tcp_listen: setsockopt(SO_KEEPALIVE) 1");
        }

        if ( connect (sd, (struct sockaddr *) &sock_name, sizeof (sock_name)) != 0 ){
                        perror("cant connect");
        }

        int n=0;
        write(sd, (const void *)request, sizeof(request));

        while ( (n=read(sd, tmp, 1024)) > 0 ){
                printf("%s\n", tmp);
                memset(tmp, 0, sizeof tmp);
        }
        write(sd, (const void *)request2, sizeof(request2));
        //n=0;
        while ( (n=read(sd, tmp, 1024)) > 0 ){
                printf("%s\n", tmp);
                memset(tmp, 0, sizeof tmp);
        }

  return 0;
}

Программа получает только ответ от первого запроса. А от второго ничего.

хотя эти отлично работаетают когда я руками их копирую.
Код

[user@localhost ~]$ nc localhost 80
GET / HTTP/1.1
Connection: keep-alive
Host: localhost


GET /cgi-bin/test.cgi HTTP/1.1
Connection: keep-alive
Host: localhost



Автор: onsql 21.12.2007, 17:28
А точно происходит второй write? Попробуй поставить перед после него отладочную печать. Также надо бы попечатать возвращаемые значения write (Никто не гарантирует что write запишет столько байт, сколько ты попросил, сколько записано - он возвращает)
Вообще говоря, поскольку сокет у тебя блокируемый и следоваетльно, ф-ии read и write не возвращают ошибок EAGAIN или EWOULDBLOCK то вот это выражение
Код

while ( (n=read(sd, tmp, 1024)) > 0 )

означает: "читать пока не произойдёт disconnect"

Автор: Олег2005 21.12.2007, 17:58
onsql прав, и ему большой плюс за это smile 
Этот фрагмент:        
Код

while ( (n=read(sd, tmp, 1024)) > 0 )
{
   printf("%s\n", tmp);
   memset(tmp, 0, sizeof tmp);
}

предполагает продолжение операции чтения до тех пор, пока не выскочит ошибка
 (-1 ) или не прийдет признак FIN n=0 - а это точно, что соединение закрыто!!!
Почему бы просто не написать 
Код

n=read(sd, tmp, 1024);
if( (n > 0 )
{
   printf("%s\n", tmp);
   memset(tmp, 0, sizeof tmp);
}
else
{
if(n==0) close(sd);
}
sleep(100);

и слать следующий запрос по еще открытому сокету!!!!

Автор: fray 21.12.2007, 20:07
Цитата(onsql @  21.12.2007,  17:28 Найти цитируемый пост)
означает: "читать пока не произойдёт disconnect"


Цитата(Олег2005 @  21.12.2007,  17:58 Найти цитируемый пост)
и слать следующий запрос по еще открытому сокету!!!!


да спасибо, за разъяснение smile
Код

        char *ptr = request;
        int k=0;
        while(*ptr++) k++;

        n = write(sd, (const void *)request, k);
        printf("writen 1: %d\n", n);
        sleep(2);
        n=0;
        n=read(sd, tmp, 370);
        printf("read1: %d\n", n);
        printf("%s\n", tmp);
        memset(tmp, 0, sizeof tmp);
        n=0;
        ptr = request2;
        k=0;
        while(*ptr++) k++;
        n=write(sd, (const void *)request2, k);
        printf("write2: %d\n", n);
        n=0;
        sleep(2);
        while ( (n=read(sd, tmp, 370) )> 0){ // тут не жалко, читаем до конца так удалось получить 2-ой ответ
                printf("read2: %d\n", n);
                printf("%s\n", tmp);
                memset(tmp, 0 , sizeof tmp);
        }

вот так работет как надо smile, то что касается двух запросов в один коннект smile

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)