Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Сети";
Текущий архив: 2007.02.25;
Скачать: [xml.tar.bz2];

Вниз

Логика работы сокетов   Найти похожие ветки 

 
_Sergey_ ©   (2006-09-05 22:57) [0]

Здравствуйте.
Недавно занялся сетевым программированием с использованием библиотеки WinSock (без применения каких-либо компонентов). Основная задача: написать сервер, который допускал бы подключение только одного клиента. Использую блокирующие сокеты, 1 поток и ф-ию select перед recv для осуществления отключения клиента от сервера по тайм-ауту передачи, клиент и сервер - консольные приложения. При этом возникли некоторые, как я полагаю, логические противоречия в работе сокетов.
1. перевожу сервер в режим ожидания подключения ф-ией listen, жду подключения от клиента, после подключения вызываю ф-ию accept. На этом этапе уже существуют 3 сокета:
1) клиентский
2) связанный с ним серверный
3) серверный в режиме ожидания подключения
Вызываю accept для 1-го клиента. После этого получаю данные от 1-го клиента. Но при этом подключаюсь к серверу 2-ым клиентом. Ф-ия connect 2-го клиента завершается без ошибки (2-й клиент добавляется в очередь на подключение). Самым "обидным" является то, что 2-ой клиент продолжает передавать данные, при этом ошибки send у него не появляется, т.е., он передает данные, которые уходят "в никуда". Вопрос: почему send отсылает данные без возникновения ошибок?
2. В обход сложившейся ситуации поступаю следующим образом: после подключения 1-го клиента вызываю CloseSocket для слушающего сокета сервера. При этом 1-й клиент передает данные без проблем (так и должно быть). Но возникает другая проблема: у 2-го клиента удачно завершается ф-ия connect (к какому слушающему сокету он подключается?). Но при первой же попытке передачи данных серверу 2-м клиентом возникает ошибка send. После этой ошибки клиент уничтожает свой сокет и переподключается. Сервер же после отключения 1-го клиента создает заново слушающий сокет и ожидает подключения. Вопрос: почему ф-ия connect 2-го клиента не завершается по ошибке (слушающий сокет на стороне сервера разрушен же)?

Изучал RFC793, RFC791, RFC768. Ситуация не прояснилась. Есть предположение, что для UDP и TCP-сокетов создаются одни и те же программные структуры (сокеты). Кроме того, есть предположение, возникшее после прочтения спецификаций, что слушающий сокет отличается от обычного только установкой спецфлага, т.е., имеет вх. и вых. буферы, и обмен информацией даже со слушающим сокетом не запрещен. И так, как в UDP реализуется передача данных до установления соединения, то реализуется ситуация 1 (данные записываются во вх. буфер слушающего сокета, ошибка не возникает). 2-я ситуация: ф-ия connect проверяет только наличие сокета, но не проверяет, слушающий он или нет. Поправьте меня, если я ошибаюсь.
Я задавал подобный вопрос на одном из форумов: http://www.delphikingdom.com/asp/answer.asp?IDAnswer=44294
Ответа на свой вопрос я, к сожалению, не получил. Буду рад любой информации: ссылки на документацию, адреса специализированных форумов, на кот. я могу получить ответы на мои вопросы.


 
Сергей М. ©   (2006-09-06 08:26) [1]


> задача: написать сервер, который допускал бы подключение
> только одного клиента


Для Win9x/Me/NT задача не решаема.
Сабж реализуем только для линейки ОС, начиная с W2k, где в отличии от предшествующих ОС функционирует опция  гнезда SO_CONDITIONAL_ACCEPT (см. Get/SetSockOpt). Только включив эту опцию и используя WSAAccept() вместо accept() можно решить задачу так как она поставлена.


 
Сергей М. ©   (2006-09-06 08:40) [2]

Впрочем можно "извратиться" и следующим образом:

При вызове listen() указать 2-м параметром (backlog queue size) значение = 1.
После успешного возврата из accept() тут же закрыть слушающее гнездо и создавать его вновь лишь при разрыве связи с клиентом.

100%-й гарантии того, что ни один клиент более не подключится, нет и в этом случае, но на практике этого достаточно для реализации сабжа.


 
_Sergey_ ©   (2006-09-06 15:27) [3]

Спасибо за ответ. Задача стоит таким образом, чтобы мое приложение (и сервер, и клиенты) работали, по крайней мере, начиная с Win98. Путем многих проб и экспериментов я реализовал логику, которая основывалась на втором посте. При проведении экспериментов с сокетами (W2k SP4)обнаружил, что параметр backlog queue size не оказывает никакого влияния на указанную ситуацию. При подключенном в данный момент 1-м клиенте 2-й подключался и при значении указанного выше параметра 1, 0, в данный момент этот параметр имеет значение SoMaxConn.
1-ый указанный Вами вариант реализовавал. Действительно, сервер не допускал подключения других клиентов, если хотя бы один был подключен (CF_REJECT). Но при оч. интенсивной нагрузке на сервер и большом кол-ве клиентов многие клиенты "зависали" (т.е., как я понял, не получали возврата из ф-ий библиотеки сокетов). Поэтому был реализован 2-й вариант. И как программист, который хочет понимать все в своей программе, возникли вопросы относительно логики работы сокетов. Соответствено, 1-ый и 2-ой вопросы в моем первом посте. Ведь протокол TCP/IP предотвращает дублирование и потерю пакетов, восстанавливает первоначальную очередность следования пакетов, предотвращает повреждение информации при передаче по линиям связи. Но, получается, то, что реализуется на нижнем уровне, то, о чем позаботились разработчики на нижнем уровне реализации, с тем приходится бороться на прикладном уровне, потому как мое приложение после введения обратной связи застраховано от потери пакета данных (пакет данных обязательно дойдет к серверу), но не застраховано от дублирования пакетов (маловероятная ситуация, но возможная).


 
Сергей М. ©   (2006-09-06 15:40) [4]


> _Sergey_ ©   (06.09.06 15:27) [3]


> при оч. интенсивной нагрузке на сервер и большом кол-ве
> клиентов многие клиенты "зависали"


Ты о чем ? О "зависании" тех самых "многих" на вызове ими ф-ции connect() ?


 
Сергей М. ©   (2006-09-06 15:46) [5]


> не застраховано от дублирования пакетов


Что за ерунда ?
Как это связано с транспортным уровнем ?


 
Сергей М. ©   (2006-09-06 16:10) [6]


> 2-ой клиент продолжает передавать данные, при этом ошибки
> send у него не появляется, т.е., он передает данные, которые
> уходят "в никуда". Вопрос: почему send отсылает данные без
> возникновения ошибок?


Потому что он в этот момент уже успешно "законнекчен".


> в данный момент этот параметр имеет значение SoMaxConn


А должен при любой логике быть = 1.

p.s.

Ты циклограмму установления TCP-соединения изучал ?


 
Медведъъ   (2006-09-06 16:55) [7]

while true do
begin
 listen
 accept
 recv
 send
 shutdown
 closesocket
end

больше одного ну никак не подключится, если поток один


 
Медведъъ   (2006-09-06 16:57) [8]

аа ступил, сорри


 
Сергей М. ©   (2006-09-07 08:41) [9]


> Медведъъ   (06.09.06 16:57) [8]
> ступил


Да уж) .. Ерунду сморозил)


 
_Sergey_ ©   (2006-09-07 17:59) [10]


> Ты о чем ? О "зависании" тех самых "многих" на вызове ими
> ф-ции connect() ?

Точно сказать не могу, на вызове какой ф-ии некоторые клиенты оказывались в "зависшем" состоянии, но логика работы клиента такова:
создать сокет, подключиться, послать нулевой пакет для проверки связи, послать информацию и через select ожидать (принять) подтверждение доставки от сервера (обратная связь). Если возникнет какая-нибудь ошибка, то уничтожить сокет и повторить все со слов "создать сокет". При этом все возникающие ошибки и некот. информация об успешно отправленном пакете записываются в логи. При небольш. кол-ве клиентов никаких проблем не возникает. Но при большом кол-ве клиентов и 1-м сервере, запущенных на локальной машине, возникает ситуация, когда через некот. время клиенты и не пишут в логи, и не обновляют статинфо на консоли, и не производят никаких других указанных действий.


 
_Sergey_ ©   (2006-09-07 18:15) [11]


> Что за ерунда ?
> Как это связано с транспортным уровнем ?

Связано, как я писал, с ПРИКЛАДНЫМ уровнем. Связано, поскольку при большой нагрузке на сервер возникает ситуация, когда, несмотря на все проверки, сервер все же не получает информацию, а клиент считает, что он ее успешно отправил. Ранее я писал клиент, основывающийся на ф-ии TransmitFile. Впоследствии мне пришлось отказаться от такой реализации.Статистика:
1) 15 клиентов на основе TransmitFile, 1 сервер, запущены локально, тайм-аут у клиента при неудачной передаче - 30 мс. На сервере фиксировалось около 20 000 успешных передач от клиента. При этом у самих клиентов суммарное кол-во успешных отправлений было где-то на 20-30 больше. Вывод: на 20 тыс отправок в жестком тестировании терялось около 20-30 пакетов.
2) 15 клиентов на основе send, те же условия.
На 20 тыс. потери около 2000 - 2500. Разница налицо.

Как в 1-м, так и во 2-м случае потери есть. А нужно, чтоб их не было. Решение: ввел обратную связь. Теперь после каждого полученного "правильного" пакета сервер отсылает клиенту сообщение, кот. клиент принимает, разрывает связь (уничтожает сокет) и формирует след. пакет.
Если подтверждение не пришло, то пакет заново перепередается.

Вывод: пришлось создавать свой простейший протокол.
Результат: кол-во успешно отправленных и успешно принятых пакетов совпадает 1:1.
Вывод: если бы не было указанных странностей в работе сокетов, то не пришлось бы вводить обратную связь. Ошибка фиксировалась бы в момент попытки выполнить сет. ф-ию.


 
_Sergey_ ©   (2006-09-07 18:21) [12]


> Потому что он в этот момент уже успешно "законнекчен".

Странно. Насколько я читал, только при вызове accept создается сокет, связанный с текущим. Для 2-го клиента я accept не вызывал. Значит, получается, и сокета для него на стороне сервера нет. Если нет связанного сокета на стороне сервера, значит, и "законнекченным" он быть не может. А данные куда-то уходят. Причем, без фиксации ошибок.


 
_Sergey_ ©   (2006-09-07 18:32) [13]


> Ты циклограмму установления TCP-соединения изучал ?

Нет. Но нашел. http://contacts.narod.ru/TCPIP/tcp18.html#t182000
Пока я не понял, как это связано с обсуждаемыми вопросами. Обмен SYN, ACK, FIN - это внутренняя логика. Она жесткая, ее изменить нельзя, пользуясь библиотекой сокетов.


 
Сергей М. ©   (2006-09-08 11:30) [14]


> Если подтверждение не пришло, то пакет заново перепередается


Это нормально для прикл.протоколов на базе UDP, но совершенно не нормально для TCP-базы.

Если подтверждение не поступило в заданный период прикладного таймайта ожидания, и при этом канал связи якобы активен, значит либо противоположная сторона соединения чем-то занята (что ненормально с т.з. оговоренной прикладной логики) либо произошел разрыв канала связи по причинам, не зависящим от партнера по соединению.
Для отслеживания таких ситуаций как правило задействуется т.н. "KeepAlive"-механизм. Суть его проста - периодически "прощупывать" виртуальное соединение на предмет отказа, посылая партнеру по соединению спец.инф.пакеты а-ля "Я живой". Если в момент отправки пакета произошла искл.ситуация на уровне Winsock-функции send(), ее следует интерпретировать как разрыв канала связи по причинам, не зависящим от партнера, не ждать более никаких ответов от партнера (ибо канала связи уже не существует) и закрывать гнездо со своей стороны.
В нек.случаях можно задействовать "KeepAlive"-механизм на внутреннем уровне WSP (см. п.п. 4.2.3.6 RFC 1122 и ф-цию SetSockOpt(SO_KEEPALIVE)), в иных же случаях механизм реализуется на прикладном уровне.


> _Sergey_ ©   (07.09.06 18:21) [12]


Изучи внимательно циклограмму стандартной процедуры установления ТСР-соединения

http://book.itep.ru/4/44/tcp_443.htm

Как видишь, accept() нигде не фигурирует - за прослушивание, прием и подтверждение вх.запросов на соединение отвечает listen-механизм, accept лишь выбирает из очереди (backlog queue) уже подтвержденных запросов (если таковые имеются) очередной запрос и создает для него отдельное гнездо, завершая тем самым создание виртуального соединения.
Т.е. акцептирование сервером соединения в этом случае происходит уже на уровне listen-механизма.

В случае же условного акцепта (SO_CONDITIONAL_ACCEPT) listen-механизм ведет себя иначе - в ответ на запрашивающий клиентский SYN-пакет он задерживает отправку  подтверждающего SYN-ACK-пакета до момента вызова WSAAccept(), которая может как подтвердить, так и отложить или отвергнуть запрос на соединение. В случае подтверждения SYN-ACK-пакет немедленно отправляется клиенту, в случае отложения запроса он ставится, если не ошибаюсь, в хвост backlog-очереди, в случае отвержения клиенту отправляется RST-пакет.


> данные куда-то уходят. Причем, без фиксации ошибок


В стандартной схеме пока сервер не выполнил accept, все, что клиент успел послать серверу, сохраняется в соотв.вх.буфере слушающего гнезда (сервер при желании может даже прочитать их с пом. recv), после accept "владельцем" вх.буфера становится тлько что созданное accept"ом гнездо.


 
Сергей М. ©   (2006-09-08 11:31) [15]


> Точно сказать не могу, на вызове какой ф-ии некоторые клиенты
> оказывались в "зависшем" состоянии


Для этого существует отладчик.


 
_Sergey_ ©   (2006-09-09 00:16) [16]


> Если подтверждение не поступило в заданный период прикладного
> таймайта ожидания, и при этом канал связи якобы активен,
>  значит либо противоположная сторона соединения чем-то занята
> (что ненормально с т.з. оговоренной прикладной логики) либо
> произошел разрыв канала связи по причинам, не зависящим
> от партнера по соединению.
> Для отслеживания таких ситуаций как правило задействуется
> т.н. "KeepAlive"-механизм.

Keep-Alive задействовать в моем случае нерационально, т.к. мой сервер предназначен для получения коротких сообщений, которые могут поступать с разным интервалом времени от многих клиентов. Клиенты при занятости сервера ожидают окончания обслуживания ним текущего подключенного клиента. Клиенты - приложения, работающие в автоматическом режиме, не ожидающие ввода команд пользователя при работе с сервером. После окончания формирования информации, подлежащей отправке на сервер, клиент пытается ее отправить. При этом пакет небольшой, времени такая пересылка занимает оч. мало, после чего (в случае успешной передачи) клиент разрывает соединение.

> в иных же случаях механизм реализуется на прикладном уровне.

Да. У меня это реализуется так: посылка перед передачей основного пакета с информацией пакета с нулевым размером. При ошибке - уничтожить сокет, создать его заново и повторить процесс передачи заново.


> Если в момент отправки пакета произошла искл.ситуация на уровне
> Winsock-функции send(), ее следует интерпретировать как разрыв канала
> связи по причинам, не зависящим от партнера, не ждать более никаких
> ответов от партнера (ибо канала связи уже не существует) и закрывать
> гнездо со своей стороны.

Я так и делаю. От сервера не пришло подтверждение - уничтожаю сокет и повторяю процедуру подключения.


> Это нормально для прикл.протоколов на базе UDP, но совершенно не
> нормально для TCP-базы.

Да. Но в свете изложенной Вами информации об механизме установления соединения не вижу другой возможности отследить ситуацию, когда данные записываются во входной буфер слушающего сокета. А когда это происходит, нужно обязательно повторить процесс передачи. Циклограмму обязательно изучу.


Для этого существует отладчик.

SoftIce-ом пользоваться так и не научился. Раньше отлаживал разные ассемблерные программки под DOS досовскими отладчиками. Так что опыт есть. Хоть и не подхлдящий для этой задачи, но принципы я прочувствовал еще тогда. Могу сказать следующее: только при интенсивном тестировании возникают такие "глюки". При нагрузке 15 клиентов + 1 сервер, 20-30 мс - тайм-аут на реконнект у клиентов, при этом через 15-20 мин. у 4-5 клиентов наступала такая ситуация. По моим представлениям такие "глюки" выловить отладчиком практически невозможно.

P.S> Спасибо за ответ. Все начинает проясняться. Но остался еще вопрос, заданный в самом начале обсуждения:
1-й клиент подключен, уничтожаю слушающий сокет, почему ф-ия connect 2-го клиента при этом не завершается по ошибке (слушающий сокет на стороне сервера разрушен же)?


 
Eraser ©   (2006-09-09 00:37) [17]

> [16] _Sergey_ ©   (09.09.06 00:16)

при чем тут софтайс??? в Делфи есть приличный встроенный отладчик..


 
_Sergey_ ©   (2006-09-09 01:46) [18]


> при чем тут софтайс??? в Делфи есть приличный встроенный
> отладчик..

При том, что 15 клиентов и 1 сервер с тайм-аутами 20-30 мс на переподключение ни на каком отладчике не отладишь. Тем более на встроенном, т.к. не знаешь, для какого из этих 15 клиентов не вернется управление из ф-ии библиотеки сокетов. А только при таком тестировании обнаруживается описываемая ситуация. Т.н. стресс-тест.


 
Eraser ©   (2006-09-09 01:57) [19]

> [18] _Sergey_ ©   (09.09.06 01:46)


> При том, что 15 клиентов и 1 сервер с тайм-аутами 20-30
> мс на переподключение

для современных локальных сетей и тем более Интернета, какие-то нереальные цифры вы хотите выжать...
imho нужно менять логику работы программы, особенно убрать вот это

> написать сервер, который допускал бы подключение только
> одного клиента


 
_Sergey_ ©   (2006-09-09 14:41) [20]


> imho нужно менять логику работы программы, особенно убрать
> вот это

Я считаю, что это как раз не нужно менять. Причины:
1) У сервера есть некот. полезная нагрузка по обработке приходящих пакетов. Нужно, чтобы в каждый момент времени только 1 пакет обрабатывался. Если я создам сервер, рассчитанный на подключение многих клиентов, то придется каким-то образом переводить подключенных клиентов в состояние ожидания, а затем высылать с сервера им спецпакеты на разрешение передачи. А это уже нехорошо, т.к. при длительной работе и некот. сбоях возможны незакрытые сокеты, зависшие соединения, и т.п. (теоретически). Сейчас же я контролирую только 1 соединение, и слежу только за его работой. И все. Больше 2 открытых сокетов мое приложение не создает. Другой способ выйти из этой ситуации: если сервер занят обработкой пришедшего пакета, можно не ожидать окончания его обработки, а накапливать все пришедшие пакеты в каком-то буфере или файле. А затем, при освобождении сервера, постепенно обрабатывать этот файл. Но это тоже не годится. Сервер должен успевать обрабатывать вх. информацию, а не просто сбрасывать ее и откладывать ее обработку на потом. Иначе теряется логика работы моего приложения.
2) Для того, чтобы отслеживать ситуацию, когда еще не создан связанный с клиентским серверный сокет, придется вводить передачу дополнительных служебных пакетов. В текущей реализации этого нет.
3) Время приема пакетов сервером некритично. Если сервер не может сейчас принять пакет, то клиент переконнекчивается через тайм-аут секунд. При этом можно быть всегда уверенным, что, если сервер не может сейчас обслужить клиента, значит, он сейчас принимает или обрабатывает данные от очередного клиента, т.е., занят полезным "делом". И в этой реализации сервер всегда будет успевать обрабатывать данные от клиентов. Если клиентов будет оч. много, то все они будут пытаться отослать информацию по тайм-ауту. Это создаст дополнительную нагрузку на сеть, но в условиях хорошего канала связи или локальной сети это несущественно.
4) Пытался написать попроще. Всего 1 клиент. Думал, по логике вещей, это должно быть реализовано. Ведь, если не отлажена нормально связь с 1 клиентом, то как можно делать многоклиентский сервер - все каналы связи, кот. он откроет, могут глючить так, как N одноклиентских серверов, а может, еще и больше. Оказалось, библиотека сокетов ориентирована на создание многоклиентских серверов, событийно-ориентированных на неблокирующих сокетах. Мне это не подходит. Нужна стабильная работа 1 канала связи. Вот и все. Неужели я так много захотел? А, между прочим, пришлось около 2 нед. создавать этоу логику, кот. реализована сейчас. И она работает. Но неужели нужно было так сложно обходить все эти проблемы? Вот у меня и возникли вопросы: может, я что-то не так делаю; может, можно проще и надежнее; может, это неправильный способ, или дело в том, что сама реализация логики в библиотеке сокетов не позволяет по-другому достичь желаемого результата; или я чего-то недопонял?

Насчет стресс-теста. Приложение в таком режиме работать не будет. Но, я как программист, должен был удостовериться в его надежной работе. И тайм-ауты у меня в реальном (а не тестовом) варианте составляют 2 секунды. Думаю, это не так мало. Причем, обсуждаемые проблемы проявляются по-одиночке за 5-7 часов работы сервера. Но проявляются. Хотя, с помощью описанных хитростей и обратной связи мне удалось свести потери на нет.


 
Eraser ©   (2006-09-09 21:13) [21]

> [20] _Sergey_ ©   (09.09.06 14:41)

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


 
_Sergey_ ©   (2006-09-09 23:10) [22]

В одновременной работе планируется:
1 ПК: сервер и клиент
+ около 10 ПК (на каждый - по клиенту) [локальная сеть небольших размеров]

Клиенты асинхронно, но довольно долго формируют пакеты. Размер 1-го пакета:
до 16 Кб максимум. Сейчас - 256 байт.


 
Eraser ©   (2006-09-09 23:13) [23]

> [22] _Sergey_ ©   (09.09.06 23:10)

понятно, значит нагрузка минимальна.. к чему тогда все эти примудрости? не прощи ли просто защитить процедуру обработки клиента, к примеру, критической секцией и не мучиться, остальные проблемы решит стек TCP?

PS как часто клиенты "обращаются" (устанавливают соединение) с сервером?


 
_Sergey_ ©   (2006-09-09 23:14) [24]

Сервер отсылает каждому клиенту клиенту только пакет с подтверждением об отправке (если успешна). Размер - 7 байт.


 
_Sergey_ ©   (2006-09-09 23:18) [25]

Частота зависит от процедуры формирования пакета. Но, чтобы клиент не занимался все время передачей пакетов, а больше времени тратил на его формирование, частота устанавливается не меньше 15 мин./клиент.

Критической секцией можно защитить. Но это не защитит от потери пакетов. А их терять нельзя, или нежелательно.


 
Eraser ©   (2006-09-09 23:18) [26]

> [24] _Sergey_ ©   (09.09.06 23:14)

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

почему не устраивает вариант с простой защитой кода от доступа из нескольких потоков? imho в данном случае - самое оно, если уж отказались от многопоточной архитектуры..


 
Eraser ©   (2006-09-09 23:21) [27]

> [25] _Sergey_ ©   (09.09.06 23:18)


> частота устанавливается не меньше 15 мин./клиент.

понятно, тоже очень мало.

> Но это не защитит от потери пакетов.

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


 
_Sergey_ ©   (2006-09-09 23:23) [28]

1 раз в 15 мин. (может, больше 15 мин.) при формировании пакета
через каждые 2 сек при занятости сервера

Критическая секция не защитит от записи пакета от какого-то клиента в буфер сокета, причем, получается, что именно слушающего. И на стороне сервера я эту ситуацию никак не отслежу. Выход: придется высылать клиентам пакет с разрешением на передачу. И только после получения разрешения клиент должен передавать пакет. Но, как мне кажется, введение еще 1 обратной связи - это не оч. красивый выход из этой ситуации.


 
Eraser ©   (2006-09-09 23:28) [29]

> [28] _Sergey_ ©   (09.09.06 23:23)


> Критическая секция не защитит от записи пакета от какого-
> то клиента в буфер сокета, причем, получается, что именно
> слушающего.

стоп-стоп! так и пусть пишет в этот буфер! при чем тут уже соединенный клиент? для него задействован уже совершенно другой сокет.

еще одно. когда на сервере формируется пакет для определенного клиента (как я понял это довольно длительный процесс) могут ли другие клиенты получать свои пакеты?


 
_Sergey_ ©   (2006-09-09 23:33) [30]

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

Нет. Не на сервере формируется пакет. Это клиенты формируют пакеты длительное время. А сервер эти пакеты только получает, и быстренько их обрабатывает, после чего опять создает слушающий сокет (т.е., снова готов к работе).


 
Eraser ©   (2006-09-09 23:34) [31]

PS чтобы данные не уходили "в никуда" самый простой и применяемый способ проверки "живости" сервера - считать с него 1 байт данных, это вполне нормальный способ.


 
Eraser ©   (2006-09-09 23:34) [32]

> [30] _Sergey_ ©   (09.09.06 23:33)
> Ваш совет, как я понял, таков: при существующей обратной
> связи с подтверждением об успешной отправке ввести обратную
> связь перед отправкой, свидетельствующей, что соединение
> с сервером установлено, и он готов получать пакет.

именно!


 
_Sergey_ ©   (2006-09-09 23:40) [33]

Хорошо. Это тоже вариант, причем более корректный с точки зрения работы с сокетами. Спасибо. Буду думать, тестировать ...


 
Eraser ©   (2006-09-09 23:44) [34]

> [33] _Sergey_ ©   (09.09.06 23:40)

в догонку:
при малых объемах информации и частой смене направления передачи данных, как в данном случае, и если критична скорость реагирования, можно отключить алгоритм Нагеля, для сокетов.
см. setsockopt + TCP_NODELAY.


 
_Sergey_ ©   (2006-09-09 23:46) [35]

Понял. Спасибо. Кстати, я устанавливаю для клиентов размер буфера для отправки в 0. Чтобы данные сразу уходили в виде пакетов в сеть.


 
Eraser ©   (2006-09-09 23:48) [36]

> [35] _Sergey_ ©   (09.09.06 23:46)

когда то тоже примерно так поступал - делал размер прикладного пакета чуть больше tcp пакета, пока не узнал про TCP_NODELAY ;)
правильнее [34] :)


 
_Sergey_ ©   (2006-09-09 23:55) [37]

Хорошо. Все понятно, придется где-то пятую часть кода сервера вырезать и переписать ;) Но, думаю, это к лучшему. Более правильная реализация стоит этого.

В любом случае о результатах сообщу в эту ветку. Если все хорошо, недельки через 1,5 максимум.

Удачи.
P.S> Если есть еще какие вопросы относительно мого приложения, с радостью отвечу.


 
_Sergey_ ©   (2006-09-09 23:58) [38]

Хотя, в такой реализации сервер будет менее защищен от "неправильных" клиентов, поскольку можно будет просто подключиться, и не посылать ни одного байта. Тогда сервер будет занят таймаут мс, после чего отключит такого клиента, но всегда же можно переподключиться. Моя же реализация иребует меньше времени на таких клиентов.


 
_Sergey_ ©   (2006-09-10 00:04) [39]

Да, последний мой пост неверен. При подключении клиента сервер просто сразу же посылает ему сообщение. Потом ждет данных, после прихода маркера окончания пакета данных отсылает подтверждение об успешной отправке и разрывает соединение. По кол-ву таймаутов сервера эти две реализации не отличаются.


 
Eraser ©   (2006-09-10 00:05) [40]

> [38] _Sergey_ ©   (09.09.06 23:58)


> Хотя, в такой реализации сервер будет менее защищен от "неправильных"
> клиентов, поскольку можно будет просто подключиться, и не
> посылать ни одного байта

это легко обойти такой схемой:
1. Клиент подключается к серверу и отсылает ему 1 байт данных.
2. Сервер пытается считать из сокета 1 байт, если не получается - закрывает сокет, если получается - входит в критическую секцию.
3. Сервер отсылает 1 байт клиенту.
4. Клиент пытается считать 1 байт, если получается - отсылает пакет, если нет - убивает сокет.
5. Сервер принимает пакет и закрывает критическую секцию.

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



Страницы: 1 2 3 вся ветка

Форум: "Сети";
Текущий архив: 2007.02.25;
Скачать: [xml.tar.bz2];

Наверх




Память: 0.62 MB
Время: 0.049 c
15-1170170721
Marker
2007-01-30 18:25
2007.02.25
Программа на заказ


15-1169584912
Елена
2007-01-23 23:41
2007.02.25
Работа. Требуется программист delphi


2-1170542958
Student_
2007-02-04 01:49
2007.02.25
Обработчик для SpeedButton


1-1167678957
Rembo
2007-01-01 22:15
2007.02.25
FindComponent и фрейм: как?


2-1170482024
vegarulez
2007-02-03 08:53
2007.02.25
Как в стринговую переменную char записать?





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский