| Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
| Форум программистов > Delphi: Сети > Нужно разослать картинку по всем подключенным клиП |
| Автор: DelphiTester 21.5.2007, 22:36 | ||
В итоге вылетают ошибки "Access Violation". Причем если не циклом, а слать только одному клиенту, то всё отлично доходит. Здесь видимо либо курсор перемещается, но куда? (я же его восстанавливаю на нулевую позицию). Либо MS вообще опустошается.. такое возможно? Как эту проблему можно решить?? Добавлено через 4 минуты и 57 секунд Приношу извинения за столь кривое оформление заголовка темы, ошибся полем не туда вписал Попробую здесь заголовок изложить: суть в том, что есть TServerSocket и подключенные клиенты, нужно разослать по ним TMemoryStream (в ней картинка). Если рассылать на один - то отлично. На много - ошибки. Есть ли идеи как их исправить? |
| Автор: Snowy 22.5.2007, 00:24 |
| Переведи сервер в ThreadBlocking режим. По дефолту он NonBlocking, что может вызывать коллизии. |
| Автор: DelphiTester 22.5.2007, 00:46 |
| Не прокатывает.. Я передаю через TCP протокол. Алгоритм у меня такой, что клиенты получают порциями большую картинку (3 мб). Причём в вышеприведённом цикле передаётся именно порция, не полная картинка. Ну в прочем, наверное, какая разница часть там или полная?! т.е. в том цикле раздача очередной части от картинки. (клиенты знают, что картинка ещё не завершилась и "ждут" её окончания). Блее подробно опишу поведение клиентов, может это как-то поможет понять Вам в чём проблема здесь.. при ThreadBlocking сервера: 1. Запущен Сервер и один Клиент - передача отличная 2. Запущен Сервер и два Клиента - один получает, у другого Access Violation |
| Автор: Snowy 22.5.2007, 00:57 |
| Разница очень существенная. Сервер - существо мультитредовое. А мемористрим расчитан только на сингловое обращение. Вывод - либо сделать множество мемористримов, либо сделать фикчированный буфер в памяти, у которого нет указателя на текущую позицию. В любом случае, при работе с множеством коннектов, стоит иметь ввиду, что пользование данными далеко не эксклюзивное, и следует изолировать переменные данные разных коннектов. В данном случае, слабое звено - свойство Position. Чтобы его изолировать - нужно использовать отдельный стрим для каждого коннекта, либо использовать единый буфер, не имеющий переменного указателя. Например массив или string. |
| Автор: DelphiTester 22.5.2007, 00:59 | ||
| String для картинки?? А разве там могут храниться без повреждения Binary-данные? Добавлено через 1 минуту и 56 секунд Интересно, а если я UDP протокол здесь буду использовать, то это сможет решить проблему? прямо на этапе её возникновения Добавлено через 2 минуты и 59 секунд если не ошибаюсь, в UDP ведь можно отправить одним большим блоком данных.. Вот только пролезет ли блок в 3-4 мб? Добавлено через 5 минут и 11 секунд
Честно говоря, не понимаю всё-таки, почему именно здесь ошибка.. Я же указатель откатываю на 0 и рассылаю с этого места поток, затем заново на 0... Мне кажется всё должно прокатывать.. |
| Автор: DelphiTester 22.5.2007, 01:21 | ||
| Блин.. всё-таки алгоритм проги чуть иной. В цикле кидается ПОЛНЫЙ пакет, а дальше уже средствами сокета он бьётся (походу частями по 8кб). Итого цикл выполняется при двух клиентах - два раза, посылая каждому по полному пакету данных. Ну а далее уже сокет дробит эти пакеты. (собираются они нормально, т.к. пакеты с "контрольными суммами" размера пакета). Тока вот видимо не всё уходит с сервера.. Всмысле не всем. Да и использовать UDP тоже не выход. На него часто навешивают жёсткие правила на файерволле... Безвыходное просто положение :( Добавлено через 8 минут и 46 секунд
И как такой "набор символов" или переменную послать клиенту? Не через SendStream же полагаю..? Я попытался создать ещё один TMemoryStream откопировать тот который хотел послать и заслать и тот и другой, причём не в цикле, а в "ручную". Ошибок нет, но до второго клиента видимо доходит пустой стрим.. |
| Автор: DelphiTester 22.5.2007, 01:44 | ||||||||
| В общем смотрите чего я достиг в этом деле. MS_Res - стрим который нужно разослать MS_Res_Bak - пытаюсь сохранять этот же стрим Этот код работает с двумя клиентами (как в НонБлокинг, так и в ТредБлокинг режимах):
Пытаюсь написать тот же код, но с циклом. И уже не получается:
У сервера возникает AccessViolation. Ясно, что в отправке ошибка. И где же тут возникает неверное обращение к памяти?? вроде всё просчитал.. нет? Добавлено через 5 минут и 28 секунд
Мда, видимо в своём вышеидущем посте я сделал именно такую ошибку... Т.е. мне теперь, что нужно этот стрим перегнать в String тип? Если так, то как отправлять его? Через SendText? Или опять через SendStream? Но если так. то непонятен смысл перегона в String, если после надо будет заново в Стрим кидать.. блин видимо я совсем запутался Добавлено через 12 минут и 33 секунды
А.. вот терь до меня дошло в чём юмор тут.. Только остаётся за гранью понимания как я "эту переменную", которая будет без указателя пошлю клиентам... через какой метод?? Добавлено через 14 минут и 51 секунду Хм.. если ты говоришь, что String хранить может и бинарные данные, то может и правда перекачать Стрим в Стринг и этот Стринг отправить через SendText? Или бред? |
| Автор: DelphiTester 22.5.2007, 09:52 |
| Забегая вперёд.. а как перевести Стрим в Стринг, если это будет приемлемым решением? Нужно ведь посимвольно, насколько я понимаю? Как достать из стрима символ, чтобы он был совместим со сторокой и добавить его успешно в эту строку? |
| Автор: drkot 22.5.2007, 09:59 | ||
Зачастую проходят пакеты не более 1024байт, все остальное перяется, зависит от настроек операционки и маршрутизаторов.
Плакаль. Собственный поток для каждого клиента или единый буфер. |
| Автор: DelphiTester 22.5.2007, 10:45 |
| drkot >> Собственный поток для каждого клиента Не понял о каком именно потоке речь идёт? >> или единый буфер. Здесь как раз подойдёт переменная String типа?? Если так, то как переслать такую переменную (там бинарные данные) и как собсно перекачать из TMemoryStream в String? |
| Автор: Snowy 22.5.2007, 11:24 | ||
|
| Автор: drkot 22.5.2007, 11:31 |
в данном случае TMemoryStream. создаеш, загружаеш данные, после отправки поток разрушаеш. Но можно и многопоточность организовать (TThread). да (как простейший вариант). тк. строки в паскале это весьма хитрый зверь; можно сказать динамический буфер на обрабатываемый на уровне языка (насколько знаю в си такого нет). ms.read(s[1], count); Добавлено через 1 минуту и 30 секунд ммммда. долго я думал |
| Автор: greenpc 22.5.2007, 11:36 |
| где-то читал что после отправки поток уничтожается Хотя могу ошибаться |
| Автор: Snowy 22.5.2007, 11:42 |
| Давайте определимся с терминологией. стримы - это стримы, а треды - это треды. А то "потоками" только запутываем, превращая текст в непонятно что. Добавлено через 2 минуты и 26 секунд Вобщем основная мысль какая: стрим не подходит для единого хранилища данных, т.к. он модифицируется в процессе чтения. Поэтому нужно использовать другое - немодифицированное хранилище. Это любой блок данных. Для простоты удобно использовать стринг. Перед отправкой забить в него содержимое стрима и рассылать уже это стринг. |
| Автор: DelphiTester 22.5.2007, 16:33 |
| Вот чертовщина! И действительно ведь работает!! Загрузил стрим в стринг как указал Snowy и через SendText. На моё удивление картинки проходят.. Всё работает! Спасибо!! |