URL: https://www.opennet.me/cgi-bin/openforum/vsluhboard.cgi
Форум: vsluhforumID9
Нить номер: 5370
[ Назад ]

Исходное сообщение
"Broken Pipe в TCL, массовый обрыв коннектов"

Отправлено KeeperR , 26-Апр-06 19:55 
Здравствуйте,

Вообщем, написал я демон для чата, на TCL. Функционально работает замечательно, но вот проблема. Например, если в чате сдит народ, не важно сколько. То в непредсказуемый момент может оборваться соединения, порядка у 40-70% пользователей.
Ошибка, которая возникает при обрыве соединений - broken pipe.
can't flush sock#xxx broken pipe

вот несколько процедур, их части:

proc connection {socket clientAddress clientPort} {
    # Отключаем блокировку сокета
    fconfigure $socket -blocking 0
    
    # Проверка на игнор хост
    if {[array exists ignored_host] && [info exists ignored_host($clientAddress)]} {
        # Хост игнорируется
        catch {close $socket}
                # лишний код убрал
        return 0
    }

        fileevent $socket readable [list read_from_socket $socket $clientAddress]
}

# Процедура чтения информации из сокета
proc read_from_socket { socket clientAddress} {
        
    # Читаем информацию из сокета
    if {[catch {set len [gets $socket data] } err] } {
        close_socket $socket "connection time out"
        return 0
    }


    if {[eof $socket]} {
        close_socket $socket "EOF"
        return 0
    }


    # Если никакой информации в сокет не передано, возвращаемся
    if {$len < 0 } {
        if {[fblocked $socket]} {
            echo "Socket $socket get's len -1, but socket is blocked, continue";
            return 0
        }
        close_socket $socket "EOF, READ EVENT, CONNECTION BROKEN: get's len -1 and socket is unbloked"
        return 0
    }
    

    if {$len == 0} {
        return 0
    }
...
...
...

# Процедура отправки сообщения в сокет
proc out { socket msg nonewline } {
        
    # Читаем информацию из сокета
    if {[catch {set len [gets $socket line] } err] } {
        close_socket $socket "connection time out"
        return 0
    }


    if {[eof $socket]} {
        close_socket $socket "EOF"
        return 0
    }


    # Если сокет сломан
    if {$len < 0 } {
        if {[fblocked $socket] != 1} {
        close_socket $socket "EOF, WRITE EVENT, CONNECTION BROKEN: get's len -1 and socket is unbloked"
        return 0
        }
    }

    # Посылаем сообщение в сокет, если происходит ошибка, то убием сокет
        if { [ catch {
        if {$nonewline == 1} {
            puts -nonewline $socket $msg
            } else {
                puts $socket $msg
                }
                flush $socket
                } err ] } {
            #Убиваем сокет
            close_socket $socket "broken pipe"
                        return 0
                        }
        return 0
}

#
# Это в теле скрипта
#

catch {socket -server connection -myaddr $host $port}

Собственно, вся проблема в том, что рубиться очень много конектов в одну секунду, обычно, раз в час

Как можно решить эту проблему?


Содержание

Сообщения в этом обсуждении
"Broken Pipe в TCL, массовый обрыв коннектов"
Отправлено KeeperR , 26-Апр-06 20:03 
Еще забыл скзать,
если не убиваю сокет при ошибки Flush, то юзеры все равно вываливаются по EOF. То что у 70 процентов юзеров сразу EOF - плохо вериться....



"Broken Pipe в TCL, массовый обрыв коннектов"
Отправлено vt , 03-Май-06 13:41 
>Еще забыл скзать,
>если не убиваю сокет при ошибки Flush, то юзеры все равно вываливаются
>по EOF. То что у 70 процентов юзеров сразу EOF -
>плохо вериться....

На первый взгляд - неплохо было бы проверять не блокирован ли socket
прежде чем в него записывать, а также добавить -buffering line в fconfigure,
раз уж чтение ведётся асинхронно, а запись - синхронно.
Второй взгляд сделать трудно )
Нужен либо полный текст, либо нормальный пример с сохранением функциональности,
но, действительно, без лишнего кода (sorry, но приведённый код - каша).
Можно также посмотреть подобные программы на wiki.tcl.tk


"Broken Pipe в TCL, массовый обрыв коннектов"
Отправлено KeeperR , 07-Май-06 20:07 
Я впринципе это зделал, проверял на блокировку сокет (зделал уже
поже). Но
проблема оставалась :).

1. Я тут разговаривал с одним человеком, он мне посоветовал использовать
потоки или разные интерпритоторы, но думаю, что это увеличит нагрузку
в разы. Потоки еще нужно указыать при компиляции. Это плохо.

При этом блокировать сокет.
Сейчас провер опыт. Я посылаю в сокет демона - символ x и жду 100
секнуд, после этого посылаю в сокет \n. В результате, демон не
принимает ни одного конекта в течение 100 сек, и вообще, как-бы виснит. Это как-то
лечиться?

2. И еще, если можно, помогите советом. Сейчас нагрузка на ЦП - 3-5%, при
80-100 человек в чате. В пиках до 50-70%. Я подумываю поставить
задержку.
after 100 например в одном цикле получения новых сообщений. Это может
привести к обрыву соединений? Тоесть, одим словом - это безопасно или
нет, или есть другие способы оптимизации?

3. Broken pipe, означет ли это невозможность востановления сокета, и
его обязательно нужно закрыть? Ведь сам по себе сокет не закрылся, а
proken pipe может быть .

Как посмотреть на то, что если я буду исполозовать заведомо большой
буфер, и я даже если сокет будет заблокирован , то я буду выполнять
puts но при этом , не выполнять flush. Как только сокет будет свободен
- произовадить flush. И если размер буфера достигнит критического -
рвать сокет по connection timeout.