Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Логика работы сокетов [D7, Win95/98, WinME, NT4, Win2k, WinXP]


Страницы:   1 2 3 4 5

_Sergey_ ©   (2006-09-05 22:57:00) 

Здравствуйте.
Недавно занялся сетевым программированием с использованием библиотеки 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
Ответа на свой вопрос я, к сожалению, не получил. Буду рад любой информации: ссылки на документацию, адреса специализированных форумов, на кот. я могу получить ответы на мои вопросы.


_Sergey_   (2006-09-18 13:26:00) [1]

Спасибо за помощь. Попробую задать вопрос или найти информацию.


Eraser   (2006-09-17 14:31:00) [2]

> [83] _Sergey_ ©   (17.09.06 14:23)

на сколько мне известно, Делфи 7 тоже глючила с включенным HT.
Тут нужно смотреть, какие подводные камни есть, при использовании этой технологии. В книге "Внутреннее устройтсво Виндовз" Солмона с Руссановичем эту информацию, при желании можно найти.

Так же задайте вопрос по HT в "WinAPI" или "Основной" конференции этого сайта, дело в том, что многие специалисты по внутреннему устройству ОС, в сетевую конференцию не читают :)


_Sergey_   (2006-09-17 14:23:00) [3]

С последним заявлением я согласен. Статистика и вероятность не на моей стороне :) Но, как Вы можете прокомментировать такую ситуацию:
- при включенном HT тестирование приводит к вышеуказанным ошибкам;
- при выключенном HT программа может работать в условиях тестирования сутки, и ни одной ошибки не возникает.

В своей программе я не использую ф-ий работы с многопроцессорными системами. Более того, можно подумать, что я неправильно синхронизирую потоки, и такая синхронизация "проходит" на однопроцессорной системе, но не "проходит" на многопроцессорной. Но у меня и поток ведь один. Нечего там синхронизировать.

P.S> Личный опыт: у знакомого плагин браузера на основе DJVU Reader намертво зависал при открытии соотв. файла, причем каждый раз в разные моменты времени. Иногда удавалось просмотреть 2 странички документа, иногда 3-4. Причем одного и того же файла. У него: P4 3.0 HT, WinXP Pro SP1 Rus. При выключении HT проблема исчезла. А вот поставил он Win2k Pro SP4 Rus. И при включенном HT тот же плагин для просмотра *.djvu работал прекрасно. И что теперь думать? На что грешить? Просмотрщик, Win или HT?


Eraser   (2006-09-16 23:38:00) [4]

> [81] _Sergey_ ©   (16.09.06 21:23)
> Надо полагать, что, наверное, ошибка вкралась или в библиотеке
> сокетов, или в компиляторе, или в стандартных юнитах.

из своего и не только своего опыта скажу так - 95%, что это ошибка в вашемкоде.


_Sergey_   (2006-09-16 21:23:00) [5]

Надо полагать, что, наверное, ошибка вкралась или в библиотеке сокетов, или в компиляторе, или в стандартных юнитах. Ведь, на момент написания некоторых из этих продуктов HT еще не было, и адаптировать их под эту технологию никто не мог. Но что сделаешь, я так понял, исправить это нельзя. Спасибо за помощь. Буду пытаться сделать так, чтоб мою программу использовали. А HT придется отключать в BIOS на тех машинках, где эта технология присутствует. Будем надеяться, что на Intel Core 2 Duo и будущих 4-ядерных настольных процессорах будет все работать как надо. Ведь все-таки будут не виртуальные процессоры, как сейчас, а "реальные". Хотя, и их не скоро купят. Цены ведь еще кусаются.


Eraser   (2006-09-15 23:00:00) [6]

> [79] _Sergey_ ©   (15.09.06 22:13)

ну что ж.. скорее всего ошибка в 17 строке, как говорится.. просто на процессоре с HT, вероятность её возникновения больше.


_Sergey_   (2006-09-15 22:13:00) [7]

Использование SetThreadAffinityMask не помогло. Привязал всех клиентов на машинке с P4 3.0 GHz HT к 0-му процессору командой SetThreadAffinityMask(GetCurrentThread, 1). ОС - WinXP Pro SP2. При этом при включенном HT, запущенных 39 клиентах и 1-м сервере с периодичностью в 15 мин. клиенты "вываливаются" с MessageBox-ами с сообщениями об ошибках работы с памятью, причем с разными адресами. Примеры:
;-------
Инструкция по адресу "0x00140190" обратилась к памяти по адресу "0x98449844". Память не может быть "written".
"OK" -- завершение приложения
;-------
Инструкция по адресу "0x77f745cc" обратилась к памяти по адресу "0xffffffff". Память не может быть "read". "OK" -- завершение приложения
;-------
Инструкция по адресу "0x00140199" обратилась к памяти по адресу "0x00002930". Память не может быть "written".
"OK" -- завершение приложения
;-------
Инструкция по адресу "0x77f745cc" обратилась к памяти по адресу "0x00000007". Память не может быть "written".
"OK" -- завершение приложения
;-------
Инструкция по адресу "0x00000000" обратилась к памяти по адресу "0x00000000". Память не может быть "read". "OK" -- завершение приложения
;-------
Причем частота появления ошибок увеличивается при активном параллельном использовании "тяжелых" сторонних программ во время проведения теста (Photoshop, FineReader, ...), особенно при их запуске/завершении.
Дополнительная информация: В своих программах использую такие юниты: SysUtils, WinSock, Windows, Classes. Перезагружаю машинку, выключаю в BIOS-е HT, провожу тот же тест - никаких сообщений об ошибках. Все чисто. Что посоветуете, какие мысли по поводу вышеизложенного?


_Sergey_   (2006-09-14 22:22:00) [8]

Все понятно. Как протестирую реализацию со SetThreadAffinityMask - напишу про результаты.


Сергей М.   (2006-09-14 13:59:00) [9]


> _Sergey_ ©   (14.09.06 13:42) [76]


Чем дальше в лес, тем больше дров)
Начали за здравие - ограничение числа одновременно обслуживаемых клиентов, а продолжили за упокой - работа со строковыми данными.

Ну никак не связаны эти две темы !

Ну хорошо, поговорим "за упокой" ..
Вот ты вызвал recv(), прочитал N байт в указанный буфер. Ну и делай с ними все что душе угодно ! Хоть как строковые данные интерпретируй их, хоть как двоичные, хоть с asm, хоть без asm - winsock'у это абсолютно фиолетово, это уже прикладнойуровень.


> можно применять массив char, и вручную копировать столько
> символов, сколько вернет recv


Да что хочешь, то и применяй)
К winsock это, повторяю, не имеет никакого отношения.
Буфер м.б. любого типа - хоть char, хоть byte, хоть что угодно...
Имея в буфере некие данные, ты волен трактовать их содержимое так как этого требует логика программы.


_Sergey_   (2006-09-14 13:42:00) [10]


> Ох и ересь ты несешь)

Прочитал в книге. Если ересь, то поправьте меня, и скажите, как правильно, если не сложно конечно. Но у меня есть такая проблема, и мне нужно найти ее решение. В частности, можно применять массив char, и вручную копировать столько символов, сколько вернет recv. Но, как известно, некот. ф-ии работы со строками написаны на asm, и поэтому более быстродействующие. Поэтому предпочтительнее не копировать строки посимвольно, а применять ф-ии для работы со строками. Неужели я и в этом неправ? ;) Или, в условиях большой производительности современных ПК не имеет значения, применеяется ф-ия, написанная на чистом asm, или на языке высокого уровня?


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


> Есть провайдеры и конторы, которые используют Win2003 Server
> для предоставления разл. услуг. Я не буду спорить по поводу
> идиотизма такого решения, но это есть


"Маздаем" принято обзывать линейку ОС Win9x/Me.


> Приемные и передающие буфера сокетов - это массивы PChar.
>  Так уж винда сделана. Для копирования из буфера нужно применять
> ф-ии, работающие с PChar (null-terminated strings)


Ох и ересь ты несешь)


Eraser   (2006-09-13 22:18:00) [12]

> [72] _Sergey_ ©   (13.09.06 20:57)


> > Только идиоту придет мысль размещать серьезную серверную
>
> > логику на маздайной платформе.
> > Маздай - платформа для рабочих станций, но никак не серверная)
>
>
> Есть провайдеры и конторы, которые используют Win2003 Server
> для предоставления разл. услуг. Я не буду спорить по поводу
> идиотизма такого решения, но это есть.

при чем тут win2k&? маздайная платформа это win95/98/me :)


_Sergey_   (2006-09-13 21:04:00) [13]


> Хм...я,например, сделал сабж.
> Каков был подход :
> -на сервере при каждом новом клиенте я создаю НОВЫЙ поток,
>  в поток передаю некоторую структуру(в одном из полей структуры
> присутствует CountThread,т.е. кол-во работающих потоков).
>
> -создавшийся поток первым делом проверяет эту структуру(а
> именно CountThread) и если он больше 1,то
>
> begin
>    ShutDown(Sock,1);
>    CloseSocket(Sock);
>  end ;
>
> т.е. принудительно оборвать связь с клиентом.
> Вот,собственно, и все. Работает сабж на Win98,WinXP.
> Код пока не привожу,надо оформить и исправить некоторые
> ошибки :)

Спасибо. Я понял Вашу реализацию. Но я уже реализовал сабж. Причем, как я скромно полагаю, более правильным способом: я просто-напросто не вызываю accept для 2-го и последующих клиентов. И отключать мне поэтому некого, т.к. никто лишний и не подключен (сохраняются ресурсы системы, на кот. стоит сервер; да и зачем устанавливать соединение для др. клиентов, если этого и не надо, а затем отключать их?). И оба (сервер и клиент) моих приложения работают под Win 9.x и WinNT. Разве что под Win95 не проверял. Но, подозреваю, что и без обновления до WinSock 2.2 под Win95 тоже будет работать.


_Sergey_   (2006-09-13 20:57:00) [14]


> Только идиоту придет мысль размещать серьезную серверную
> логику на маздайной платформе.
> Маздай - платформа для рабочих станций, но никак не серверная)

Есть провайдеры и конторы, которые используют Win2003 Server для предоставления разл. услуг. Я не буду спорить по поводу идиотизма такого решения, но это есть. Платформа для рабочих станций - это да. Сам *nix не юзаю. Но признаю его как серьезное семейство ОС, но только в отношении построения на их базе серверов, в плане удобства работы десктопные решения, основывающиеся на *nix недалеко ушли от своих серверных собратьев (ИМХО, можно тут затеять спор, но спорить мне не к чему на эту тему). Куда удобнее Win. Дак вот. ВСЕ машинки, на кот. планируется запускать клиентов, работают именно под Win, т.к. это ПК обычных рядовых пользователей. Не больше, не меньше. И никто не будет там ставить ничто другое. И с LiveCD никто загружаться не будет, как и прерывать свою работу.
Поэтому и клиент, и сервер (не обязательно, можно 1 машинку под платформой NT и найти) должен работать под управлением Win. Причем клиент - обязательно на ВСЕХ версиях Win. Поэтому pipes по постановке задачи не подходят.


> КЕМ (или чем) расценивается ?

Приемные и передающие буфера сокетов - это массивы PChar. Так уж винда сделана. Для копирования из буфера нужно применять ф-ии, работающие с PChar (null-terminated strings) - например, StrLCat я использую для объединения частей данных при recv. Но в null-terminated strings нету в 0-м байте строки, или где-либо еще счетчика кол-ва символов в строке. Конец строки "опознается" по 0-му байту. Вот и получается, что, встретив 0-й байт, ф-ия считает, что данных в буфере нет. А они там есть. Вопрос: как их оттуда "забрать" и "склеить" (append) с уже существующей строкой?


> ... сдалась SetProcess/ThreadAffinityMask, если ты изначально
> планируешь однопоточность своего сервера ?

Это был вопрос, кот. имел своей целью подтвердить/опровергнуть мои догадки по использованию SetThreadAffinityMask. Зачем мне нужно использовать эту ф-ию?

> 5) осталась проблемка: с включенным HT при стресс-тесте
> иногда клиенты вылетают с сообщением об ошибке обращения
> к памяти, адреса все время разные. При выключенном HT такая
> проблема исчезает. Вероятная причина: винда или ее библиотеки
> (включая сетевые) не всегда правильно работает на многопроцессорной
> машинке (процессоры хоть и виртуальные, но их все же формально
> 2 шт.). В старой реализации такая прблема проявлялась раза
> в 4 чаще.



> возможно в данном случае поможет ф-ия SetThreadAffinityMask,
>  которая позволяет "привязать" поток к определенному процессору.
> . не знаю как оно будет работать с HT.. думаю нормально
> )


GanibalLector   (2006-09-13 17:09:00) [15]

Хм...я,например, сделал сабж.
Каков был подход :
-на сервере при каждом новом клиенте я создаю НОВЫЙ поток, в поток передаю некоторую структуру(в одном из полей структуры присутствует CountThread,т.е. кол-во работающих потоков).
-создавшийся поток первым делом проверяет эту структуру(а именно CountThread) и если он больше 1,то

begin
   ShutDown(Sock,1);
   CloseSocket(Sock);
 end ;

т.е. принудительно оборвать связь с клиентом.
Вот,собственно, и все. Работает сабж на Win98,WinXP.
Код пока не привожу,надо оформить и исправить некоторые ошибки :)


Сергей М.   (2006-09-13 13:59:00) [16]


> _Sergey_


Нафих тебе, скажи на милость, сдалась SetProcess/ThreadAffinityMask, если ты изначально планируешь однопоточность своего сервера ?


Eraser   (2006-09-13 13:52:00) [17]

> [65] _Sergey_ ©   (13.09.06 11:41)


> Остался вопрос по SetThreadAffinityMask. Если имеется многопоточный
> сервер, то:
> 1) Если NT, то определить кол-во установленных процессоров
> через GetSystemInfo.
> 2) Для каждого подкл. клиента создавать свой поток, привязывая
> его SetThreadAffinityMask сначала к 0, след. поток - к 1-
> му, ... N, затем снова 0-му процессору?

можно так, можно менее экономичный вариант - взять и привязать весь процесс к опр. процессору SetProcessAffinityMask.


Сергей М.   (2006-09-13 12:35:00) [18]


> как работают протоколы, основывающиеся на TCP/IP, и передающие
> бинарные файлы? Ведь в них однозначно встречаются 0-е байты


так и работают.

Самому TCP-протоколу безразлично содержимое транспортируемых с его помощью данных. Все остальное - право и обязанность прикладных надстроек над TCP.


Сергей М.   (2006-09-13 12:33:00) [19]


> Почему только под управлением Windows?


Потому что это твой случай, судя по перечню ОС в сабже.
В целом ничего не имею против *nix на эту тему.


> "Windows Me/98/95:  Named pipes cannot be created." (с)


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


> при копировании из приемного
> буфера этот байт расценивается как конец строки?


КЕМ (или чем) расценивается ?


_Sergey_   (2006-09-13 12:04:00) [20]

И еще один вопрос: как передавать 0-й байт (00h). Ведь при копировании из приемного буфера этот байт расценивается как конец строки? Или его надо заменять на другую комбинацию символов? Но тогда как работают протоколы, основывающиеся на TCP/IP, и передающие бинарные файлы? Ведь в них однозначно встречаются 0-е байты.


Страницы:   1 2 3 4 5

Наверх

Титульная страница Поиск, карта сайта Написать письмо