![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Странности у TTcpClient и TTcpServer
SpellCaster © (2006-07-04 19:52:00)Товарищи! Для решения глобальной задачи написал простенький тестер. Есть TTcpClient и TTcpServer. Сервер по таймеру пишет в поток данные (допустим, текущие секунды), а клиент постоянно в цикле читает из этого буфера. Так вот, по идее после первого прочтения буфер должен быть пуст - но нет, там остается второй байт, извлекаемый из буфера только при втором прочтении. При этом количество прочитанных байт (TcpClient1.ReceiveBuf(Buf,size) ) всегда почему-то равно 255. Как можно проверить целостность полученного сообщения, если потенциально его размер неизвестен?
И еще. Пытаюсь "навесить" серверу события, типа OnAccept, но из всех вызывается почему-то только CreateHandle. Причем если событиям присвоены обработчики, при закрытии формы возникает Exception, без обработчиков все нормально. Это что-то у меня глючит, или как?
Заранее спасибо.
procedure TForm1.Button1Click(Sender: TObject);
begin
Timer1Timer(nil);
Server1.Active:=True;
Client1.Active:=True;
Client1.Connect;
end;
procedure TForm1.Timer1Timer(Sender: TObject);
begin
s:=inttostr(SecondOf(Time));
StrCopy(PChar(Buf),PChar(s));
size:=Length(s);
Label1.Caption:=s;
Server1.SendBuf(Buf,size);
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
Buf:=PByte(AllocMem(MaxMsgLen));
end;
procedure TForm1.Button2Click(Sender: TObject);
var
msg: array of Byte;
i: byte;
begin
i:=client1.ReceiveBuf(Buf,size);
SetLength(msg,3);
msg[0]:=Buf^;
inc(buf);
msg[1]:=Buf^;
msg[2]:=0;
log(PChar(@msg[0]));
log(inttostr(i));
end;
Сергей М. (2006-07-10 15:02:00) [21]
> SpellCaster (10.07.06 14:20) [20]
> Оно же должно выполняться при коннекте, а коннекта у меня
> не происходит
Событие OnConnect как раз и является фактом успешно установленного коннекта.
> ctive по-прежнему остается False
Значит режим - неблокирующий.
SpellCaster (2006-07-10 14:20:00) [22]
> medved_68
> А событие ОНКОННЕКТ клиента привязал в нити???? Это если
> не в блоке.
А зачем? Оно же должно выполняться при коннекте, а коннекта у меня не происходит.
> Slym
> Если ошибка не вывалилась значит выполнилось.
К сожалению, нет. Active по-прежнему остается False, ничего не передается.
Slym (2006-07-10 10:10:00) [23]SpellCaster (07.07.06 17:31) [15]
1. Почему не выполняется коннект сокета в методе Execute потока
Если ошибка не вывалилась значит выполнилось.
SpellCaster (07.07.06 17:31) [15]
2. Надо ли юзать TWinSocketStream, при условии что вероятны обрывы связи,
Условия не причем, ни кто тебе не мешает выдрать код ожидания из TWinSocketStream
SpellCaster (07.07.06 17:31) [15]
Надежен ли ReceiveLength, т.е. вероятна ли ситуация
Надежен и вероятна :) с оговоркой ReceiveLength выдаст количество инфы во внутреннем буфере сокета и эту инфу ты можешь спокойно без блокировки потока считать, но байтом больше ты можешь встать в ожидание или сгенерировать ошибку сокета
Но
Ketmar (2006-07-09 11:54:00) [24]>medved_68 © (08.07.06 16:00) [17]
не думаю, что в неблокирующем нет тайм-аутов. но точно не знаю -- никогда не использовал этот режим. %-)
medved_68 (2006-07-08 16:00:00) [25]
> 2. навечно оно там не зависнет. в конце концов вылетит по
> тайм-ауту.
Если в неблокирующем режиме то навряд ли, будет ждать пополнения буфера из сокета.
> SpellCaster
> Проблема такая: создаю новый класс нити (Thread), уже в
> ней создаю Клиентсокет
> вроде бы нормально, но в процедуре Execute почему-то не
> выполняется коннект (active:=true)! Т.е. эта строчка просто
> проходится, и прога выполняется дальше.
А событие ОНКОННЕКТ клиента привязал в нити???? Это если не в блоке.
> Ладно, перешел на блокирующие сокеты... вроде во всем разобрался,
> только неясно: в этом случае обязательно юзать TWinSocketStream?
>
Нет необязательно. Можешь читать теми же методами их никто не отменял. Другое дело как узнать когда необходимо читать??? Ведь в блоке уведомлений в виде событий нет!!!! А у TWinSocketStream есть таймаут по которому можно продолжать выполнение треда даже если нет ожидаемых данных. :)))
> 2а. Надежен ли ReceiveLength, т.е. вероятна ли ситуация,
> когда там ненулевое значение, а при чтении буфера связь
> разрывается?
ненулевое значение установится только при полном приеме из сокета</B. если произойдет сбой во время приема очередного блока то просто будет либо ИС, либо ОНКЛИЕНТЕРРОР, в зависимости от режима работы сокета.
>
> а при чтении буфера связь разрывается?
Ты читаешь буфер когда он уже загружен т.е. очередной сеанс связи прошел успешно. Наверное действительно необходимо:"Если хочешь поработать, ляг поспи и все пройдет". :))))
Ketmar (2006-07-08 13:27:00) [26]2. навечно оно там не зависнет. в конце концов вылетит по тайм-ауту.
SpellCaster (2006-07-07 17:31:00) [27]Снова я )))
Проблема такая: создаю новый класс нити (Thread), уже в ней создаю Клиентсокет. Все вроде бы нормально, но в процедуре Execute почему-то не выполняется коннект (active:=true)! Т.е. эта строчка просто проходится, и прога выполняется дальше. Ладно, перешел на блокирующие сокеты... вроде во всем разобрался, только неясно: в этом случае обязательно юзать TWinSocketStream?
Итак, вопросов 2:
1. Почему не выполняется коннект сокета в методе Execute потока
2. Надо ли юзать TWinSocketStream, при условии что вероятны обрывы связи, а навечно зависший на строчке fClient.Socket.ReceiveBuf(fDestBuf^,size); код не подходит?
2а. Надежен ли ReceiveLength, т.е. вероятна ли ситуация, когда там ненулевое значение, а при чтении буфера связь разрывается?
...немного путано, но уже конец рабочего дня, а спать жуть как охота ))
SpellCaster (2006-07-06 17:57:00) [28]Ладно, пока что фурычит, начнет глючить - снова начну всех тормошить :). А с выбором способа приема подожду, пока не появится реальный сервак, буду уже на нем тестить.
Всем спасибо за внимание и помощь! =)
medved_68 (2006-07-06 12:46:00) [29]
> SpellCaster
> medved_68
> А что мешает? ;)
Прогресс, блин....:))))
> Трабла в том, что надо принимать двоичные данные - а я не
> уверен, будет ли Инди передавать строки с нулями в середине.
>
Будет и нормально. Я например если размеры передаваемого блока меняются перед передачей конкретного блока забиваю в буфер его размер обычно INT64 а при приеме первого блока считываю его в отдельную переменную затем принимаю весь блок, сливаю в поток и проверяю совпадают ли размеры. Если да то можно и подтвердить прием тут уж конкретно от алгоритма, можно и запрос на повтор выставить серверу, и нормально ничего не теряется и не съедается. Что ИНДИ что СерверСокет работают одинаково. Вообщем все траблы от непродуманности прием-передачи по каналу (по крайней мере у меня были), как только решил сей вопрос, стало фиолетово какой компонент использовать они примерно все одинаковы в смысле работы с каналом связи. Вопрос в удобстве использования.
P.S. Кстати передачей я пользуюсь только SendStream, удобство так сказать ,отправил поток и забыл....
Untermensch (2006-07-06 11:31:00) [30]Я имел ввиду, что если клиент и сервер пишутся в рамках одного проекта, то проще перешифровывать данные канала в BASE64 чтоб не ломать потом голову что и как потерялось, а если использовать собственную базу символов для кодирования, это ещё и быстро отобьёт желание у сниферменов ломать данный протокол.
А насчёт нолей - они нормально проходят если в середине, проблема когда 0 стоит перед маркером конца, т.к. инди например его зачем то сьедает.
SpellCaster (2006-07-06 11:20:00) [31]Untermensch
Были бы строки, я бы не стал так париться - со строками вроде всё нормально пашет. Трабла в том, что надо принимать двоичные данные - а я не уверен, будет ли Инди передавать строки с нулями в середине.
medved_68
А что мешает? ;)
Untermensch (2006-07-06 09:56:00) [32]Странно написал уже несколько программ с инди10, всё замечательно работает, очень удобная потоковая структура сервера, единственное что, для передачи пользую обычные строки кодированые в чём нить типа base64, т.е. текст и типовой маркер конца сообщения #13#10. В качестве буфера везде испольуются обычные длинные текстовые строки дельфи (вернее адрес первого байта строки).
Сбор и разбор строк выполняет сама программа. На сервере - службе 30 клиентов, 50 потоков, общение с базой и периферией, и ни одной жалобы на indy система рабоает сутками без перезапуска. Утомляет правда отлов ексепшона на клиенте, если он сервера не видит (чего им, событий не хватило, что ли, ну нет сервера и нет, падать то зачем). А кодировка блока в base64 как раз и призвана исключить всё загадочное поведение канала (типа Трима младших кодов меньше 32). А ещё, одно замечание, у инди есть какое то ограничение на размер буфера в сокете, не помню точно, но при больших размерах она выдаёт ексепшон) потому большие пакеты желательно делить на маленькие и собирать там же где осуществляется кодировка. Оптимально передавать где то по 4-16кб.
medved_68 (2006-07-05 17:13:00) [33]
> SpellCaster
> Забил на все эти странные компоненты
Тоже Выход!!!! Я бы тоже забил но.....:)))))
SpellCaster (2006-07-05 17:02:00) [34]Забил на все эти странные компоненты, заюзал чисто ТхххСокет. Пока что вроде бы пашет. Повесил чтение данных на ClientSocket.OnRead.
medved_68 (2006-07-05 14:10:00) [35]Исправь передачу буфера как [5] тогда будет все чики чики
SpellCaster (2006-07-05 14:08:00) [36]Поправка: оказывается, я юзал один и тот же буфер для принятия и получения ((. После того как сделал два буфера, выяснил, что данные вообще не приходят! Постоянно возникает эта долбаная ошибка 10035!
*спокойно, спокойно, дыши глубже...*
Буду разбираться с ТхххСокет.
medved_68 (2006-07-05 14:05:00) [37]>
> SpellCaster
Server1.SendBuf(Buf,size);
посылаешь неправильно если Buf:string то SendBuf(Buf[1],size);
а если Buf:array чего то то SendBuf(Buf[0],size); где size размер либо строки либо отправляемого буфера.
> Это не Инди, это ТTCPServer. Инди у меня вообще глючит безбожно,
> посылает вроде нормально, а получает - лабуду всякую :(
Неправда. При таком подходе как [0] ты и с TServerSocket, TClientSocket получишь лабуду на приеме. А насчет ТTCPServer я правда всего пару прог на нем рихтовал, нормально тоже работает, зря на него бочку катишь!!!!
SpellCaster (2006-07-05 13:37:00) [38]
> Странно в byte пытаешься записать size:=Length(s); Тогда
> уж читай в цикле и набивай msg. А условие выхода = size;
>
Так s - это строка, ее длина не больше 255...
А ReceiveBuf(Buf,size); почему-то всегда возвращает -1 (который из-за беззнаковости byte превращается в 255).
К тому же если повесить на клиента событие OnError, то перед каждым действием возникает ошибка "10035 Операция на незаблокированном сокете не может быть завершена немедленно". Клиенту я поставил blockmode=bmNonBlocking, т.к. в противном случае прога виснет.
> size:=int64;
> загоняй его в буфер первым передавай и при приеме проверяй
> по нему все ли считал :)))
Вообще да, в реальном серваке будут посылаться сообщения с сигнатурой окончания, можно будет по ним проверять. Просто меня удивило, что вроде бы байт уже прочитан, а в буфере он остается.
> А где ты увидел у IdTCPServer такое событие????
Это не Инди, это ТTCPServer. Инди у меня вообще глючит безбожно, посылает вроде нормально, а получает - лабуду всякую :(
P.S. Фух, наконец-то нашел, куда бормановцы засунули TServerSocket
и TClientSocket. Надо поробовать с этими компонентами.
medved_68 (2006-07-05 10:39:00) [39]
> Так вот, по идее после первого прочтения буфер должен быть
> пуст - но нет, там остается второй байт, извлекаемый из
> буфера только при втором прочтении.
> var
> msg: array of Byte;
> i: byte;
> begin
> i:=client1.ReceiveBuf(Buf,size);
Странно в byte пытаешься записать size:=Length(s); Тогда уж читай в цикле и набивай msg. А условие выхода = size;
> Как можно проверить целостность полученного сообщения,
> если потенциально его размер неизвестен?
size:=int64;
загоняй его в буфер первым передавай и при приеме проверяй по нему все ли считал :)))
> Пытаюсь "навесить" серверу события, типа OnAccept,
А где ты увидел у IdTCPServer такое событие????
SpellCaster (2006-07-05 10:10:00) [40]Почему? Глючный? Дело в том, что сервер будет не мой, удаленный, а я сейчас набросал нечто вроде эмулятора. Все, что от него требуется - раз в секунду бросать данные.
Или лучше юзать как Серверсокет, так и Клиентсокет?