| Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
| Форум программистов > Delphi: Сети > Сокеты |
| Автор: WERITAS 29.4.2007, 12:59 | ||||
| Сразу скажу, что ни разу не пользовался компонентами Delphi для работы в сети. Где здесь у меня ошибка: Для сервера:
Для клиента:
Не прилетает ни одно из сообщений :( |
| Автор: Exai1e 29.4.2007, 13:07 | ||||
Сервер
Клиент
пасмари, пример рабочий, мб поможет... |
| Автор: WERITAS 29.4.2007, 13:57 | ||||
Что это? У меня в Delphi7 такого нет |
| Автор: Exai1e 29.4.2007, 14:10 |
| Эт я сам делал http://stream.ifolder.ru/1843699 |
| Автор: Sanchezzz 29.4.2007, 22:39 |
| сокеты лежат отдельно в папке ...Delphi\bin\dclSocket70.bpl |
| Автор: Exai1e 29.4.2007, 22:58 | ||
| WERITAS, Надо было сразу уточнить про что ты... а то ~
|
| Автор: WERITAS 30.4.2007, 07:58 | ||||||
| Exai1e А я это и цитировал:
|
| Автор: Exai1e 30.4.2007, 10:54 |
| Exai1e, Ну когда я отписывался цитата была другая |
| Автор: WERITAS 30.4.2007, 11:16 |
| Ну надо было выждать всего полминуты Всё равно спасибо) Я с компонентов TcpClient/TcpServer перешёл к TClientSocket/TServerSocket |
| Автор: Saygak 2.5.2007, 12:55 | ||
| Вопрос, собственно, Exai1e: ты приводишь пример чата и все работает, но при изменении Socket.SendText(...) на Socket.SendStream(...) почему-то возникает ошибка. промер программы:
|
| Автор: Snowy 2.5.2007, 13:02 |
| А ты попробуй использовать локальные переменные, а не глобальные - всё само пройдёт Вот где тут ms создаётся? или битмап? и прочие переменные? И кто их ещё юзает в данный момент? |
| Автор: Saygak 2.5.2007, 13:16 | ||||
| Snowy: щас приведу полный код. Сервер:
Клиент:
там еще у сервера 2 форма с предполагаемыми настройками сервера... Надеюсь понятно, что я копирую рабочий стол на канву битмапа, сохраняю в поток и отправляю клиенту... Добавлено через 2 минуты и 12 секунд Некоторые участки были написаны с использованием Delphi Russian Knowledge Base... Добавлено через 11 минут и 7 секунд а переменные ms, DC и BitMap не локальные для того, чтобы не тратить время на их создание и уничтожение при каждом обтащении клиета |
| Автор: Snowy 2.5.2007, 13:46 |
| Просто для теста, создай стрим локально, загрузи в него битмап с диска и отправь. |
| Автор: Saygak 2.5.2007, 15:50 | ||||
| все время возился... нашел, только что ClientCoket получает данные порциями (у меня 4096 б). Попробовал исправить передачу и получение данных. Сначала отправляю строку на сервере:
На клиенте:
(код подсмотрел в книге "Программирование в Delphi глазами хакера") Snowy, инициализация переменных внутри процедур (локально) у меня ничего не дает. Теперь ситуация такая: Данные передает (вродебы), но куда они деваются непонятно... PS. Как говорил один из пилотов: "Ничего не понимаю"... |
| Автор: Saygak 2.5.2007, 16:32 | ||
| фух, работает. Snowy, спасибо за совет:
Не сразу догадаешься, что этот стрим сам удаляется (наверно)... А получать данные пришлось всетаки как я указывал раньше (по частям)... программы вроде работают и ладно, будем улучшать... |
| Автор: Misha_White 14.5.2007, 11:31 |
| Такая же проблема... А Картинку нельзя как картинку отправить? Типа TJPEGImage? И как отправить через TSocket операцией Send а получить Recv? Вроде отправляет и получает, но при попытке обращения пишет ошибку доступа к памяти... Помогите пожалуйста... Курсовик горит... |
| Автор: Snowy 14.5.2007, 11:36 |
| Нет. Объект отправить нельзя. Нужно сохранить в стрим и отправлять стрим. Потом получить стрим и загрузить. |
| Автор: Misha_White 14.5.2007, 11:40 |
| Со стримом такая же система... Уже замучился... Добавлено через 1 минуту и 38 секунд При получении не ругается, а при попытке загрузки из стрима - ошибка... |
| Автор: Snowy 14.5.2007, 11:44 |
| Значит неправильно передал или принял стрим. |
| Автор: Misha_White 14.5.2007, 11:49 |
| JpegIm:=TJPEGImage.Create; MyStream:=TMemoryStream.Create; err:= recv(cSocket,MyStream,SizeOf(MyStream),0); If Err=Socket_Error then MessageBox(NULL,'Ошибка при получении!','Error',MB_OK); // MyStream.Seek(0,soFromBeginning); JpegIm.LoadFromStream(MyStream); // Здесь ругается!!! Image1.Picture.Assign(JpegIm); MyStream.Destroy; JpegIm.Destroy; А как? Добавлено @ 11:57 Записи же отправляются... |
| Автор: Misha_White 14.5.2007, 12:06 |
| |
| Автор: Snowy 14.5.2007, 12:22 |
| Круто Я ошибся - оказывается ты неправильно передаёшь и неправильно принимаешь Я ж тебе говорю - нельзя передавать объекты. Разницу между объектом и записью ощущаешь? Тебя не смущает, что SizeOf(MyStream) равно 4 байта? В твоём коде вообще всё неправильно. Нужно отправлять размер картинки перед передачей. Перед приёмом нужно подготовить буфер и читать в него. Причём, как передавать, так и читать нужно не объект, а данные. Для MemoryStream это Memory и Size. Посмотри хотя бы код в этом топике. Почитай пример передачи картинки в http://www.drkb.ru/ Попробуй поиск - передача картинки или файла обсуждалась неоднократно. Добавлено через 3 минуты и 20 секунд http://forum.vingrad.ru/forum/topic-112719/index.html |
| Автор: Misha_White 14.5.2007, 12:30 |
| Спасибо, о сенсей! Че-то ничего не могу понять... Ща попробую поиск... |
| Автор: Snowy 14.5.2007, 12:31 |
| Я ж тебе уже всё нашёл и линк дал |
| Автор: Misha_White 14.5.2007, 12:44 |
| Спасибо! Ща буду разбираться... Сколько уже мучаюсь... В книжках только по TserverSocket and TClientSocket... и там вроде есть Метод SendStream... А их не использую... А DRKB, блин, 30 метров весит... Я его неделю буду качать... :-( Добавлено через 13 минут и 50 секунд Как все запущено... |
| Автор: Misha_White 14.5.2007, 13:08 |
| |
| Автор: Saygak 14.5.2007, 13:15 |
| Привет Misha_White, у меня тоже была проблема. Тебе надо отправлять картинку? Я уже ковырятся с этим. Как я делаю: в событии OnRead у ServerSocket - сохряняю картинку в стрим (у меня TMemoryStream) - оправляю строку 'Size:'+TStream.Size+#0; (Socket.SendText(...)) - потом отправляю стрим (Soket.SendStream(...))(не вызывай после этой строки метод Free стрима) на клиенте при OnRead у ClientSocket - получаю строку (например 'Size:4000'#0) создаю TMemoryStream, строковую переменную, и инициализирую переменные (размер получаемых данных(DataSize из строки 'Size:4000'#0), и логическую переменную(Recived) что начат прием данных). при слудующем приеме данных если Recived = true тогда записываю данные из полученной строки в стрим, как только размер полученных данных (TStream.Size) равен размеру получаемых данных (DataSize) загружаю картинку из стрима. Все. |
| Автор: Misha_White 14.5.2007, 13:58 |
| Saygak, Спасибо! Но я не использую TServerSocket! У меня сокет типа TSocket... Отправлять могу только Send(), а получать Recv()... Вот такая проблема... |
| Автор: Misha_White 14.5.2007, 16:18 |
| Snowy, Если сначала отправлять размер картинки... и что, следом слать саму картинку? Но как узнать, что получать? Т.е. я же не знаю, картинка это или нет... Допустим мы сохраним размер в Integer переменной и отправим и что, сразу шлем картинку(стрим)? А в клиенте подрят получаем сначала размер стрима и следом сразу стрим что ли? Че-то ниче не пойму... |
| Автор: Snowy 14.5.2007, 16:40 |
| Да, отправляем сначала размер стрима - 4 байта. Потом сразу данные, указанного размера. А клиент сидит и ждёт, пока ему пришлют 4 байта. Получает, выделяет буфер и начинает читать, пока не прочитает указанное кол-во байт. |
| Автор: Misha_White 15.5.2007, 01:49 | ||||||||
Почему именно 4 байта? Если Stream.Size=~64134, если это размер моего стрима, то почму нельзя указать его?
Как этого добиться? У меня клиент в это время должен отправлять свои данные этому серверу... А если подрят вызывать Recv, то ерунда же получится... CЕРВЕР
КЛИЕНТ
Только не смейтесь пожалуйста, о сенсей! Как нужно сделать? |
| Автор: Misha_White 15.5.2007, 16:05 | ||||||
Snowy,
А у меня процедурка TClientForm.Socket_Proc_Read_Close(var Msg:TMessage); вызывается только при прибытии данных или если поступило сообщение о закрытии сокета сервером!
Т.е. сообщение NETEVENT_MSG; поступает от сервера только когда он передал данные, либо когда закрыл соединение...
Т.е. нужно написать Send(vSocket,DispStream.Memory^,DispSize,0); и все начнет работать? А почему в Делфи у DispStream нету свойства(или метода) Memory? Т.е. DispStream.<Ctrl>+<Spase> ничего не дает? правда я не разыменовывал Memory и не компилировал... Но сейчас попробую... Добавлено через 7 минут и 12 секунд Snowy, |
| Автор: Snowy 15.5.2007, 16:30 |
| Разумеется. recv принимает только те данные, которые есть в буфере сокета. Ты должен проверять - если принято меньше, чем указано байт, то нужно подождать, когда придут остальные данные и продолжить приём. Это же не UDP - данные идут потоком, а не приходят за один раз. Поэтому верх у тебя нормальный - он принялся. А полосы ниже - мусор, вместо принятых данных. Остальные данные должны были придти позже. |
| Автор: Misha_White 15.5.2007, 16:36 |
| Snowy, Спасибо! Завтра попробую... или сечас... уже поздно, надо спать... Т.е. получили кусок и вышли из процедуры? Или заLOOPить прием стрима? |
| Автор: Snowy 15.5.2007, 16:46 | ||
Выбор стратегии за тобой. |
| Автор: Misha_White 15.5.2007, 16:49 |
| Snowy, |
| Автор: Misha_White 15.5.2007, 17:45 | ||
Snowy,
Не могу понять, то-ли я стрим не так принял или че... Ну размеры вроде совпадают... Вот думаю, может во время приема Seek-ать надо в конец полученного куска? Или все-таки с JPEG проблема? Добавлено через 11 минут и 40 секунд Snowy, Достал я тебя походу... Ладно, завтра буду разбираться с этим делом... |
| Автор: Snowy 15.5.2007, 18:56 |
| Угу. Memory всегда указывает на начало стрима. То есть ты постоянно перезаписываешь начало, а дальше не пишешь. Заведи какой-нить буффер килобайта на 4, читай в него и скидывай в стрим, пока не накидаешь нужный размер. В стрим скидывай через метод Write. |
| Автор: Misha_White 16.5.2007, 08:25 |
| Snowy, Че-т ничерта не пойму... А буфер какого типа брать? И как потом Write-ом кидать? |
| Автор: Snowy 16.5.2007, 10:21 |
| Любого. Например string отлично подходит. Только сначала нужно ему длину определить SetLength(s, 4096); А передавать recv и Write не сам стринг, а s[1] |
| Автор: Misha_White 16.5.2007, 10:25 | ||
| Misha_White, Понятно, попробую... А во Write надо вторым параметром Count передавать... Это и будет 4096? Добавлено через 4 минуты и 24 секунды Snowy, Или Столько, сколько возвратит Recv? Добавлено через 8 минут и 32 секунды
Че-то не так.... Добавлено через 11 минут и 6 секунд |
| Автор: Snowy 16.5.2007, 10:46 |
Убери установку размера стрима. Он сам растянется по мере записи в него. |
| Автор: Misha_White 16.5.2007, 11:13 | ||
это - размер принятого... Чтобы сравнить с DispSize...
Во Write что писать? Err или 4096? |
| Автор: Snowy 16.5.2007, 11:15 |
| А зачем? У стрима уже есть Size. err |
| Автор: Misha_White 16.5.2007, 12:30 | ||
| Snowy, Я написал
Но после приема стрима, прога не выходит из цикла, а начинает с начала приема данных (хотя с сервера ничего не отправлялось)и, считывая DispSize , выдает ошибки... |
| Автор: Snowy 16.5.2007, 13:30 |
| Принимай не DispSize, а 4096! У тебя мимо буфера выливается |
| Автор: Misha_White 16.5.2007, 13:42 |
| Snowy, Could not convert variant of type (Null) into (Int64)... Добавлено через 41 секунду Заругался клиент |
| Автор: Snowy 16.5.2007, 13:49 |
| В каком месте? Поменяй условие цикла на > Пиши в стрим только, если err > 0 |
| Автор: Misha_White 16.5.2007, 13:57 |
| Snowy, Дело в том, что стрим записывается полностью, и картинка появляется, но процедура пытается еще считывать данные из сокета, а Reciv у нас уже False, поэтому она пытается принять размер стрима... и так раза 4-5... потом только приходит новая картинка... походу... Добавлено через 57 секунд Snowy, Я Аську поставил... |
| Автор: Snowy 16.5.2007, 14:14 |
| Это просто потому, что картинка шла несколькими частями. А сокет у тебя асинхронный. Вот и накопилась очередь сообщений о приходе данных. О отрабатывает она только по выходу из обработчика. Сразу выходи из обработчика, если в буфере пусто. |
| Автор: Misha_White 16.5.2007, 14:19 |
| Snowy, Каким Макаром? Добавлено через 7 минут и 18 секунд Snowy, Выйти из обработчика? |
| Автор: Snowy 16.5.2007, 15:15 |
| Exit |
| Автор: Misha_White 16.5.2007, 15:24 |
| Snowy, Из обработчика... дело походу в том, что продолжает поступать сообщение NETEVENT_MSG... Вот... Поэтому процедура повторно(раз5-8) вызывается... |
| Автор: Snowy 16.5.2007, 15:27 |
| Разумеется вызывается. Я даже написал почему. А будет картинка большего размера - будет больше вызываться. В самом начале обработчика вставь проверку на наличие данных в буфере. Если данных 0, то сразу делай Exit; |
| Автор: Misha_White 17.5.2007, 08:59 | ||||
| Snowy, Сделал подругому!
но почему-то ругается при второй попытке... в строке
Т.е., когда принимаем вторую картинку... Принимается вроде как надо(размеры совпадают)... а при попытке загрузить в Image рагается, блин Не могу понять почему... |
| Автор: Misha_White 17.5.2007, 11:22 |
| Snowy, |
| Автор: Misha_White 17.5.2007, 11:49 |
| Snowy, Есть идеи, почему так? |
| Автор: Misha_White 18.5.2007, 15:56 |
| Misha_White, Такой вопрос: почему передавать нужно S[1]? что это значит? |
| Автор: Snowy 18.5.2007, 16:03 |
| s[1] - первый символ. Это и есть начало буфера, поскольку сам стринг - указатель, а передать нужно буфер, а не указатель на него. |
| Автор: Misha_White 18.5.2007, 16:10 |
| Snowy, Понятно. Спасибо! А я ведь так и не понял почему он второй раз не грузится... Сегодня в универе запустил на двух машинах, дак она с третьего раза не захотела загружаться... |
| Автор: Misha_White 19.5.2007, 13:51 |
| Snowy, Если ошибка возникает при третьем приеме, то она возникает при попытке создать стрим... |