Здравствуйте,Вообщем, написал я демон для чата, на 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}
Собственно, вся проблема в том, что рубиться очень много конектов в одну секунду, обычно, раз в час
Как можно решить эту проблему?
Еще забыл скзать,
если не убиваю сокет при ошибки Flush, то юзеры все равно вываливаются по EOF. То что у 70 процентов юзеров сразу EOF - плохо вериться....
>Еще забыл скзать,
>если не убиваю сокет при ошибки Flush, то юзеры все равно вываливаются
>по EOF. То что у 70 процентов юзеров сразу EOF -
>плохо вериться....На первый взгляд - неплохо было бы проверять не блокирован ли socket
прежде чем в него записывать, а также добавить -buffering line в fconfigure,
раз уж чтение ведётся асинхронно, а запись - синхронно.
Второй взгляд сделать трудно )
Нужен либо полный текст, либо нормальный пример с сохранением функциональности,
но, действительно, без лишнего кода (sorry, но приведённый код - каша).
Можно также посмотреть подобные программы на wiki.tcl.tk
Я впринципе это зделал, проверял на блокировку сокет (зделал уже
поже). Но
проблема оставалась :).1. Я тут разговаривал с одним человеком, он мне посоветовал использовать
потоки или разные интерпритоторы, но думаю, что это увеличит нагрузку
в разы. Потоки еще нужно указыать при компиляции. Это плохо.При этом блокировать сокет.
Сейчас провер опыт. Я посылаю в сокет демона - символ x и жду 100
секнуд, после этого посылаю в сокет \n. В результате, демон не
принимает ни одного конекта в течение 100 сек, и вообще, как-бы виснит. Это как-то
лечиться?2. И еще, если можно, помогите советом. Сейчас нагрузка на ЦП - 3-5%, при
80-100 человек в чате. В пиках до 50-70%. Я подумываю поставить
задержку.
after 100 например в одном цикле получения новых сообщений. Это может
привести к обрыву соединений? Тоесть, одим словом - это безопасно или
нет, или есть другие способы оптимизации?3. Broken pipe, означет ли это невозможность востановления сокета, и
его обязательно нужно закрыть? Ведь сам по себе сокет не закрылся, а
proken pipe может быть .Как посмотреть на то, что если я буду исполозовать заведомо большой
буфер, и я даже если сокет будет заблокирован , то я буду выполнять
puts но при этом , не выполнять flush. Как только сокет будет свободен
- произовадить flush. И если размер буфера достигнит критического -
рвать сокет по connection timeout.