как определить что клиент отсоединился от сокета
От: meandr  
Дата: 08.09.04 06:09
Оценка:
Приветствую.

Собственно говоря вот и весь вопрос.

Нашел у других код который определяет это через сигналы (сокеты в
ассинхронном режиме),
но не работает (проверяю через Cygwin), а именно не приходят сигналы IO.

В чём может быть дело.
Posted via RSDN NNTP Server 1.9 gamma
Re: как определить что клиент отсоединился от сокета
От: ilnar Россия  
Дата: 08.09.04 06:32
Оценка:
Здравствуйте, meandr, Вы писали:

M>Приветствую.


M>Собственно говоря вот и весь вопрос.


M>Нашел у других код который определяет это через сигналы (сокеты в

M>ассинхронном режиме),
M>но не работает (проверяю через Cygwin), а именно не приходят сигналы IO.

M>В чём может быть дело.


в select помещаешь дескриптор в exeption (третье) множество, при отключении клиента там получишь подтверждение
Re[2]: как определить что клиент отсоединился от сокета
От: meandr  
Дата: 08.09.04 06:38
Оценка:
Не работает такой метод, фиг знает почему,

но срабатывает такое:
если клиент отключается, то его сокет становится готовым на чтение,
но считывается с него 0 байт. Я смотрел и у других такое реализовано.
А разумное объеснение мне не видно
Posted via RSDN NNTP Server 1.9 gamma
Re[2]: как определить что клиент отсоединился от сокета
От: PVA  
Дата: 08.09.04 06:38
Оценка:
Здравствуйте, ilnar, Вы писали:

I>в select помещаешь дескриптор в exeption (третье) множество, при отключении клиента там получишь подтверждение

А если этот дескриптор присутствует в первых двух множествах, разве select не вернет ошибку о неверном дескрипторе?
newbie
Re[3]: как определить что клиент отсоединился от сокета
От: ilnar Россия  
Дата: 08.09.04 06:42
Оценка:
Здравствуйте, meandr, Вы писали:

M>Не работает такой метод, фиг знает почему,


M>но срабатывает такое:

M> если клиент отключается, то его сокет становится готовым на чтение,
M> но считывается с него 0 байт. Я смотрел и у других такое реализовано.
M> А разумное объеснение мне не видно

0 — если не читать 0 байт (указать размер буфера 0), тоэто означает eof для сокета. а если не eof и данных нет, то вернется -1, и код ошибки вроде EAGAIN
Re[3]: как определить что клиент отсоединился от сокета
От: ilnar Россия  
Дата: 08.09.04 06:48
Оценка:
Здравствуйте, PVA, Вы писали:

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


I>>в select помещаешь дескриптор в exeption (третье) множество, при отключении клиента там получишь подтверждение

PVA>А если этот дескриптор присутствует в первых двух множествах, разве select не вернет ошибку о неверном дескрипторе?

нет, я всегда в купе со чтением или записью (множествами) обязательно вношу и в третий, т.е. если ожидаю чтения, то чтение и третий, и т.д. :

case READ:
    FD_SET(fd, &inFd);
    FD_SET(fd, &excFd);
    if(fd > maxFd) maxFd = fd;
    break;
case WRITE:
    FD_SET(fd, &outFd);
    FD_SET(fd, &excFd);
    if(fd > maxFd) maxFd = fd;
    break;
case READWRITE:
    FD_SET(fd, &inFd);
    FD_SET(fd, &outFd);
    FD_SET(fd, &excFd);
    if(fd > maxFd) maxFd = fd;
    break;


кроме того, при чтении еще фиксирую eof (клиент закрыл сокет), если recv(fd, readBuf, nToIo, 0)==0 при nToIo>0
Re: как определить что клиент отсоединился от сокета
От: meandr  
Дата: 08.09.04 07:18
Оценка:
Ну а всё таки почему обнаружение дисконекта не происходит в следующем коде:
А также вот такой вопрос: А правильно ли отправлять клиенту что — либо сразу после принятия соединения?

use POSIX;
use IO::Socket;
use IO::Select;

$|=1;

sub nonblock {
my $socket = shift;
$flags = fcntl($socket, F_GETFL, 0);
fcntl($socket, F_SETFL, $flags | O_NONBLOCK );
}

$SERVER = new IO::Socket::INET(LocalPort => 88,
LocalAddr => 0,
Timeout => 5,
Reuse => 1,
Listen => 5) or die "can't create socket";

nonblock($SERVER);
$list = new IO::Select ();
$list->add($SERVER);

while(1) {
foreach $fh ($list->can_read(0.05)) {
if($fh == $SERVER) {
if($new = $SERVER->accept()){
nonblock($new);
$list->add($new);
print "accept ".fileno($new)."\n";
print {$new} ("HTTP/1.1 200 ok\r\ncontent-type: text/plain;\r\n\r\n") || die($!."\n"); #правильно ли это делать сдесь?
};
}
else {
my $char;

# unless(sysread($fh, $char,1)){
# print ("\n\n".'отсоединение '.fileno($fh)."\n\n");

# $list->remove ($fh);
# close($fh);
# }
# else{
# print $char;
# };


while(sysread($fh, $char,1)){
print $char;
};

};
};

foreach $fh ($list->can_write(0.05)) {
print {$fh} fileno($fh)."<br>\n" || die $!;
};

foreach $fh (IO::Select->select(undef, undef, $list, 0.05)){
print 'here' #Сюда никогда не попадаем.
};
};
Posted via RSDN NNTP Server 1.9 gamma
Re[2]: как определить что клиент отсоединился от сокета
От: butcher Россия http://bu7cher.blogspot.com
Дата: 08.09.04 07:36
Оценка:
Здравствуйте, meandr, Вы писали:

M>Ну а всё таки почему обнаружение дисконекта не происходит в следующем коде:

Потому что вы не проверяете на возниконовение exeption. Используйте метод select, а не can_read. В нём можно указать списки дескрипторов сразу для чтения, записи и исключений.
    list->select($readers, $writers, $exept [, $timeout]);

M>А также вот такой вопрос: А правильно ли отправлять клиенту что — либо сразу после принятия соединения?
В вашем случае, ИМХО, сначала нужно принять запрос, а потом уже отвечать.
M>    print {$new} ("HTTP/1.1 200 ok\r\ncontent-type: text/plain;\r\n\r\n") || die($!."\n");   #правильно ли это делать сдесь?

Если уж вы пишете подобие Web-сервера, то отвечайте его кодами (я про die).

Нет ничего невозможного..
Re[3]: как определить что клиент отсоединился от сокета
От: meandr  
Дата: 08.09.04 08:06
Оценка:
А вот это тогда что:

foreach $fh (IO::Select->select(undef, undef, $list, 0.05){
print 'here' #Сюда никогда не попадаем.
};

И вы всё таки не отведили на мой вопрос, наверное непонятно сформулировал:

Коректно ли сразу после выполнения accept произвести отправку чего либо, те:
$fd accept (...);
write ($fd, 'erwerwerwerwer');
Posted via RSDN NNTP Server 1.9 gamma
Re[3]: как определить что клиент отсоединился от сокета
От: Keen the Green Россия  
Дата: 08.09.04 09:38
Оценка:
Здравствуйте, meandr, Вы писали:

M>Не работает такой метод, фиг знает почему,


M>но срабатывает такое:

M> если клиент отключается, то его сокет становится готовым на чтение,
M> но считывается с него 0 байт. Я смотрел и у других такое реализовано.
M> А разумное объеснение мне не видно

Во, и у меня те же грабли.
Только у меня 50/50: то как описано, то получаю ошибку сокета 10053.

Ну, да, раз говорите, что так и должно быть, щас диагностику допишу
K.T.G.
Re[4]: как определить что клиент отсоединился от сокета
От: butcher Россия http://bu7cher.blogspot.com
Дата: 08.09.04 09:54
Оценка: +1
Здравствуйте, meandr, Вы писали:

Посмотрел сейчас man'ы, в exeption помещаются только дескрипторы, на которые пришли OOB данные. Если соединение закрывается, то срабатывает readset или writeset.
Нужно анализировать возврат функция чтения или записи.

M>И вы всё таки не отведили на мой вопрос, наверное непонятно сформулировал:

M> Коректно ли сразу после выполнения accept произвести отправку чего либо, те:
M> $fd accept (...);
M> write ($fd, 'erwerwerwerwer');
Можно, если хотите. Если не хотите, можете подождать .

Нет ничего невозможного..
Re: как определить что клиент отсоединился от сокета
От: Аноним  
Дата: 08.09.04 22:37
Оценка:
Здравствуйте, meandr, Вы писали:

M>Приветствую.


M>Собственно говоря вот и весь вопрос.


M>Нашел у других код который определяет это через сигналы (сокеты в

M>ассинхронном режиме),
M>но не работает (проверяю через Cygwin), а именно не приходят сигналы IO.

M>В чём может быть дело.


SYNOPSIS
#include <sys/socket.h>

int getpeername(int s, struct sockaddr *name, socklen_t *namelen);

DESCRIPTION
Getpeername returns the name of the peer connected to socket s. The namelen parameter
should be initialized to indicate the amount of space pointed to by name. On return it
contains the actual size of the name returned (in bytes). The name is truncated if the
buffer provided is too small.

Оно?
Re[3]: как определить что клиент отсоединился от сокета
От: MaximE Великобритания  
Дата: 13.09.04 06:17
Оценка:
meandr wrote:

> но срабатывает такое:

> если клиент отключается, то его сокет становится готовым на чтение,
> но считывается с него 0 байт. Я смотрел и у других такое реализовано.

На самом деле это стандартный и переносимый способ.

> А разумное объеснение мне не видно


Разумное объяснение в том, как происходит graceful close. Клиент вызвает shutdown(socket, SHUT_WR). Этот вызов отправляет серверу FIN и переводит сокет клиента в состояние FIN_WAIT_1. В этом состоянии клиент ждет ACK от сервера, который TCP стэк сервера посылает автоматом, поэтому в состоянии FIN_WAIT_1 клиент пребывает совсем недолго, если только нет никаких сетевых проблем. После получения FIN от клиента сокет сервера становится готовым на чтение (read event, о котором можно узнать при помощи poll или select) с 0 байт, что для сокета означает EOF. На полученный FIN TCP стэк сервера отсылает клиенту ACK и переходит в состояние CLOSE_WAIT. Сокет клиента, получив этот ACK от сервера переходит в состояние FIN_WAIT_2, ожидая FIN от сервера. Чтобы отослать клиенту FIN, сервер должен со своей стороны вызвать shutdown(socket, SHUT_WR).

В манах сказано, что close на серверном сокете автоматом делает shutdown, но в ходе экспериментов на red hat 9 было выяснено, что это не так и следует вызывать shutdown(socket, SHUT_WR) явно, иначе после close серверный сокет так и останется висеть в CLOSE_WAIT, а клиентский в FIN_WAIT_2 (т.е. будут orphan'ами).

--
Maxim Yegorushkin
Posted via RSDN NNTP Server 1.9 gamma
Re[5]: как определить что клиент отсоединился от сокета
От: PVA  
Дата: 14.09.04 13:37
Оценка:
Здравствуйте, butcher, Вы писали:

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


B>Посмотрел сейчас man'ы, в exeption помещаются только дескрипторы, на которые пришли OOB данные. Если соединение закрывается, то срабатывает readset или writeset.

B>Нужно анализировать возврат функция чтения или записи.

О чем я и говорил выше.
newbie
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.