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

Вниз

TStringList и Сокет... Вопрос простой ;))   Найти похожие ветки 

 
SemFLY   (2002-09-26 20:57) [0]

Как мне по сокету отправить список найденных файлов в виде StringList’а, далее принять их клиентом и вывести в ListBox построчно ?

Я так понимаю отправлять надо так
ServerSocket1.Socket.Connections[0].SendText( SpisokFailov + #13#10);
а вот как принять ?

Или может отправлять надо не так, как лучше осуществить это ?

Спасибо ! ;)))


 
Song   (2002-09-26 21:02) [1]

Вообще обычно отсылают клиентом:
ClientSocket1.Socket.SendText()
А принимает сервер на событии TServerSocket.onClientRead


 
SemFLY   (2002-09-26 21:07) [2]

Ну хорошо пусть так... посылает клиент, а принимает сервер...

Как мне упаковать все имена найденных файлов в список TStringList, правильно их принять сервером и поместить в ListBox


 
SemFLY   (2002-09-26 22:06) [3]

Мастера помогите, у меня где-то
пример был подевал его куда-то... :(((


 
Wonder   (2002-09-26 22:22) [4]

А почему именно в StringList?


 
Dot   (2002-09-26 22:32) [5]

for i := 0 to myspisok.count do
serversocket1.socket.connections[0].sendtext(spisok+#13#10);
serversocket1.socket.connections[0].sendtext(#0);

на сервере принимаешь до #0 и по линиям суешь


 
SemFLY   (2002-09-26 22:59) [6]

Dot, Спасибо ! ;)))

Wonder, можешь свой вариант предложить, может он проще.


 
Rouse_   (2002-09-27 00:53) [7]

Как вариант, я в некоторых программах делаю следующим образом:

for i:= 0 to StringList.Count-1 do
Msg := Msg+"^"+StringList.Strings[i];
serversocket1.socket.connections[0].sendtext(Msg);

А на приеме:

StringList.Text := StringReplace(Msg,"^",#13#10,[rfReplaceAll]);

Желаю удачи


 
VID   (2002-09-27 10:07) [8]

TO Rouse_: а если в одной из строк StringList"а будет строка содержащая символ "^" ? ;)

TO SEMFLY:
Есть StringList со список строк, который надо отправить на сервер.
В программе-клиенте пишешь:

Client.Socket.SendText(StringList.Text);

В сервере пишешь:
Procedure ServeronClientRead(...);
VAR ST:TStringList;
S:String;
begin
S:=Socket.ReceiveText;
ST.Text := S;
end;

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


 
Song   (2002-09-27 10:25) [9]

Вообще, если в переданной строке уже есть #13#10 то на приёме просто приравняйте принятую строку в TStringList.Text. Итемы разобьются по строкам сами.


 
SemFLY   (2002-09-28 12:18) [10]

Тут по ходу ещё вопрос возник, отправляя список найденных файлов проскакивает префикс строки, которым я указываю клиенту, что отправлен список найденных файлов.

Префикс такой "#4"
Почему так происходит ?

Отправка списка:

while FindNext(SearchRec) = 0 do
begin
if (SearchRec.Attr or faReadOnly or faHidden or faSysFile or faArchive) <> 0 then
ServerSocket1.Socket.Connections[0].SendText("#4"+SearchRec.Name+#13#10);
SearchRec.Name := "";
end;


Префикс проскакивает не при каждой передаче, а иногда через раз, иногда через 3-4 раза, переменно короче...
И появляется в Memo в таком виде
#4Test.txt
#4File.doc
... и т.д.

Принимаю так


...
RecText := "";
RecText := ClientSocket1.Socket.ReceiveText;
MsgTF := Copy(RecText,1,2);
If (MsgTF = "#4") then
begin
MyList := TStringList.Create;
MyList.Text := RecText;
Form4.ListBox1.Items.AddStrings(MyList);
MyList.Clear;
RecText := "";
end;
...



 
SemFLY   (2002-09-28 12:22) [11]

Извеняюсь, появляется в ListBox"e, а ни в Memo... ;)


 
Aralekin   (2002-09-28 12:37) [12]

А в файл все сохранить и отправить в потоке нельзя? Так помоему проще будет.


 
m-Sergo   (2002-09-28 13:08) [13]

Я не стал читать всё, слишком долго... и поэтому не знаю есть ли там такое

сервер.Socket.SendText(твой_TStringList.CommaText)
...
твой_TStringList.CommaText := клиент.ReceiveText


 
dot   (2002-09-28 19:25) [14]

дополнение к m-Sergo запятую в передатчике меняй на чтото или посылай #13#10


 
Subfire   (2002-09-29 02:24) [15]

Господа...сорри, но вы тормоза немного :_
Нормальные люди делают так:
отправка
..
xxTStringList : TStringList;
...

..Socket.SendBuf(xxTStringList,SizeOf(xxTStringList));
получка
..Socket.RevieveBuf(xxTStringList,Socket.Receive.Lenght);


 
VID   (2002-09-29 11:37) [16]

TO SemFLY:
1. Нафига отправлять имя найденного файла сразу же после его нахождения ? НЕ лучше ли сначала скопить список найденныйх файлов в клиенте, а потом, сразу отправить весь список ? А как отправить уже было сказано, и не один раз: либо через CommaText либо просто через Text
2. MyList.Text := RecText;
Это что шутка сезона ? Ты ведь присваиваешь списку MyList полученный текст от клиента, В ЧИСТОМ ВИДЕ! Без его обработки. Я хочу сказать, что иногда было бы не плохо перед тем, как писать MyList.Text := RecText вызвать проц-ру:
Delete(RecText, 1,2); ;)
3. Ещё раз повторю, что тобою не учтены случаи когда пакет отправляемый может быть слишком длинным, и поэтому будет приходить по частям, либо наоборот, два пакета могут прийти одновременно в "склееном" виде. Решение этих двух проблем, вообще отдельный разговор (Кстати неплохо бы объявить конкурс, на лучшее решение этой проблемы)

А вообще, лучше вместо #4 используй нечто типа #F, или какую-нибудь другую букву.


 
Subfire   (2002-09-29 16:18) [17]

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

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


 
VID   (2002-09-29 16:43) [18]

TO Subfire: ну вообще-то, то что я описал п3 это ещё не значит, что для меня это великая нерешимая проблема. Я то её решил для себя, но метод не очень оптимален, и поэтому было бы неплохо увидеть более лучшее решение.
А теперь позволь придраться. Что за сигнатуру ты предлагаешь использовать ? Ведь надо учесть что:
1. Речь идёт о методе SendText
2. В качестве сигнатуры по-идее не может быть использован ни один символ, и ни одно сочетание символом, т.к. теоретически, в самом пакете также может быть использована сигнатура, которая по идее "не сигнатура" :)
3. А как насчёт "склеенных" пакетов ? (хотя конечно на самом деле - это действительно придирка ;)


 
Subfire   (2002-09-29 17:57) [19]

VID ©
Я ни в коем случае не говорил, что ты не можешь...ты предложил конкур - я принял вызов :)
Впринципе, основная заточка - для STREAM ориентированных сокетов, но тем не менее:
по п.1 Пусть будет SendText,ReceiveText - это не играет роли...
2.Если SendText то мы полагаем что в качестве данных будут символы...т.е. ограниченный диапазон по ASCII...Ну и ладно!
Что нам мешает использовать ДВА байта по упр. символам если нам не будет хватать оставшегося диапазона...?
Скажем, первый пакет будет:
STR_TO_SEND:=#01+#10+"посылаем текст";
01 говорит что это сигнатура, следующий байт - тип пакета.
А сигнатура конца скажем 50FF$ по приколу...или 0000
И все...
Затем, впринципе, сигнатура может быть и любое число от 0-255...в том числе и сивол!
Я же описал принцип...когда мы получаем пакет, и буфер накопления пуст, то это ОДНОЗНАЧНО свидетельствует что это первый ( а может и последний пакет) из блока данных. ЗНАЧИТ ПЕРВЫЙ БАЙТ ЭТО ОДНОЗНАЧНО СИГНАТУРА...Если в конце сообщения есть сигнатура конца - значит это нефрагментированный блок и можно что-то делать и очищать буфер...В противном случае, КАЖДЫЙ последующий пакет, это ОДНОЗНАЧНО фрагменты блока, если в конце нет сигнатуры конца...Так что эти пакеты не снабжаются сигнатурой типа.
Значит, только сигнатура конца должна быть такой, чтобы не совпасть с блоком данных...и все.
А по п.3...что значит склеенных? Не понимаю тебя...по спецификации Ethernet такого быть не может...Ведь как только я делаю SendText,SendBuf, или send (на Api) то СРАЗУ формируется пакет и отсылается....Так что склеится на этом уровне он не может....Если ты говоришь о склейке на прикладном уровне - т.е. в за один раз мы отправлаем несколько логических блоков..ну тады это головная боль для программы которая получает эти данные...


 
VID   (2002-09-29 22:05) [20]

2Subfire:
Мдаа.. Ну ладно, начнём с п3 :)
Известно ли тебе, что иногда в случае отправки текста SendText() возможна такая ситуация:
Client.Socket.SendText("Это первый посылаемый пакет");
Client.Socket.SendText("Это второй посылаемый пакет");

А на сервере Socket.ReceiveText будет содержать текст:

Это первый посылаемый пакетЭто второй посылаемый пакет

Вот такие-вот дела. Всё ещё будешь говорить, что это проблема программы-сервера (или клиента - т.к. и у него такое возможно с той же вер-тью) ?
Вот что я называю "склеенным" пакетом, причём не претендуя на профессорский уровень точности терминологии ;)

2. СИГНАТУРЫ. Теперь, учитывая возможность "склеиваемости" пакетов, приём текста стал уже не таким простым делом. Теперь, придётся не просто наивно проверять первый символ пришедшего текста (СИГНАТУРА НАЧАЛА) и последний (СИГНАТУРА ОКОНЧАНИЯ), а также сканировать весь полученный текст, т.к. там где-то по середине может заваляться начало второго пакета :)
К чему я это ? А к тому, что меня жутко заинтересовало, что ты будешь делать если пользователю приспичит послать на сервер текст:

{
Сигнатура начала #01#10
Сигнатура окончания #02#10
}

Client.Socket.SendText("Подлый пакет от "+#02+#10+#01+#10+"пользователя!") ? ;)
И так что произойдёт в этом случае ?
Программа перед отправкой этого текста как и положено добавит СИГНАТУРУ НАЧАЛА #01+#10, и сигнатуру окончания пакета.

Теперь сервер сканирует полученный пакет:
01#10Подлый пакет от #02#10#01#10пользователя#02#10
И вполне справедливо полагает, что пришло два абсолютно разных пакета, таким образом сервер даст на исполнение два пакета:
1.Подлый пакет от
2.пользователя
Результат: НИЧЕГО! Т.е. смотрим со строны: Пользователь, послал на сервер необходимый текст. Пользователя совершенно не колышет, какие ты там сигнатуры используешь. А что он получает от сервера ? НИЧЕГО ! :)
Обыдна, да ? ;)

В-общем, твой вариант, был бы действительно прекрасен, если бы не склеивание пакетов :)
А вообще, было бы интересно послушать Malder"а, а ещё интереснее посмотреть реализацию его алгоритма принятия пакетов, в виде OP-кода :)

Этот вопрос уже обсуждался в одной из веток этой конференции.

КОНКУРС ПРОДОЛЖАЕТСЯ ! :)


 
Subfire   (2002-09-30 00:51) [21]

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


 
s002156Shurik   (2002-09-30 00:56) [22]

Думаю принцип который предложил при прошлом обсуждении Molder наиболее оптимальный.
Сам я давно решил эту проблему для себя бумаю примерно также как решил ее и ты VID. По крайней мере мое решение несколько похоже на решение Molder"а и хотя я о нем уже говорил но повторюсь.

Отправка:
пользователь создает строку "Строка пользователя"
дорабатываем строку до "<19>Строка пользователя"
отправляем
Принимаем:
1 принятый кусок строки добавляем в конец буферной строки bstr;
2 вызываем прочедуру которая
a) удаляет (если есть ;|) часть bstr до "<"; //(это на случай ошибки, правда такого явления я незамечал здесь но на всякий случай предусмотрел так спокойнее)
b) копирует участок "<число>" и достает из него число;
c) если длинна полученного буфера минус длинна участка "<число>" меньше bstr то ниче не делаем и выходим из проседуры.
иначе отрезаем от bstr участок "<число>" копируем кусок bstr длинной "число" символов в ostr, удаляем этотже кусок из bstr.
d) передает ostr кому оно надо ибо ostr это то что послал пользоатель отдельным куском.

все. Пом очень просто алгоритм работает без отказно и ниче тут непопишеш.
думаю не я один пользую такого типа алгоритм. Более рационального решения этой проблемы я невижу.


 
Subfire   (2002-09-30 02:14) [23]

VID ©
Эээ...кстати...а вопрос еще...а разве SendText позволяет отправлять что-то больше стандартной строки? Так тады это 255 байт, фрагментации 100% никакой , и в любом случае не обойтись без SendBuf :)))


 
VID   (2002-09-30 11:39) [24]

TO SubFire, s002156Shurik:
Давайте перейдём от теории к практике :)

НА сайте UBPFD я выложил юнит, реализующий принятие пакета, по алгоритму, предложенному Malder"ом.

Обсуждайте, исправляйте и оптимизируйте. Кстати, все предложения по этому юниту, лучше указывать в комментариях, на сайте UBPFD.

http://delphibase.endimus.com/?action=viewfunc&topic=nettransfer&id=10335

PS: To SubFire(30.09.02 02:14): ну а если пишем чат ? ;)


 
Polevi   (2002-09-30 12:22) [25]

2VID © (30.09.02 11:39)
Почему ты считаешь что заголовок всегда приходит целиком ?
И что получиться если я пошлю строку с цифирками в начале ???
Плохой твой пример, IMHO



 
Subfire   (2002-09-30 12:46) [26]

To VID © Неважно что мы пишем...Ты мне плиз объясни как пакет максимум в 256 байт (именно такой размер данных МАКСИМУМ за раз отправляет SendText) + заголовки...так что на протокольном и тем более транспортном уровне фрагментации быть не может - по спецификации МИНИМАЛЬНЫЙ размер пакета 589 байт...
Фрагментация может быть тока на программном уровне, когда посылаемые данные приходится нарезать на несколько строк - но это тривиальная проблемма.
Я же говорю о таком случее, когда мы посылаем заведомо большой массив данных, которые неизвестно как будет нарезать - все зависит от размера кадра.


 
exchoper   (2002-09-30 15:27) [27]

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


 
exchoper   (2002-09-30 15:31) [28]

с чего вы решили что SendText ограничиваеться 255?
вот код
function TCustomWinSocket.SendText(const s: string): Integer;
begin
Result := SendBuf(Pointer(S)^, Length(S));
end;

ограничиваеться длиной переменной String, народ это 2 Гбайта, вроде должно хватить...


 
Polevi   (2002-09-30 15:39) [29]

2exchoper © (30.09.02 15:27)
>читаете из сокета 4 байта
а если там один байт всего ?


 
Digitman   (2002-09-30 15:58) [30]

Вот поэтому - всегда делаю упор на этом - транспортный узел и должен иметь в том или ином виде т.н. "машину состояния транспорта" - TSM (transport state machine). Задача, решаемая TSM, в 1-ю очередь как раз и заключается в извещении приемо-передающего алгоритма о его очередных действиях : ждать сч-к, ждать данные и т.д. ..


 
exchoper   (2002-09-30 15:58) [31]

если пришло меньше 4х считаем ошибку приема, все-равно это не дело если пришло меньше!!!


 
Polevi   (2002-09-30 16:19) [32]

2exchoper © (30.09.02 15:58)
представьте что пришло 8192 байта, из них 8191 - первый блок, а один байт - кусочек следующего. чтож по вашему счиатть это ошибкой и рвать соединение что ли ?


 
exchoper   (2002-09-30 16:28) [33]

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


 
Polevi   (2002-09-30 16:58) [34]

это ответ на вопрос Polevi © (30.09.02 16:19) ??
мда


 
exchoper   (2002-09-30 17:12) [35]

что конкретно непонятно?


 
Polevi   (2002-09-30 18:37) [36]

пришло 8192
4 заголовок, 8187 данные
остался один байт - что ты с ним делать будешь ?
допустим у меня неблокирующий режим, какой цикл ???
со списками надо работать - пришел блок - добавили этот блок в список, затем пытаться дефрагментровать список, извлекая из него готовые блоки данных


 
Subfire   (2002-09-30 19:07) [37]

exchoper © Ничего нового ты не сказал...


 
Subfire   (2002-09-30 19:11) [38]

Мндя...по поводу длинны я чего-то стормозил... :)))


 
VID   (2002-09-30 19:17) [39]

to polevi: Да, я не учёл ситуация, когда сам заголовок может прийти неполностью.
Вот ссылка
http://delphibase.endimus.com/?action=viewfunc&topic=nettransfer&id=10335
здесь находится обновленная версия юнита.

to SubFire: Что за непонятные спецификации? Лично у меня, если TClientSocket отправляет 16384 симв текста, то например TServerSocket может за раз принять 8192 символов. Вообще складывается впечатление что ты что-то путаешь.


> exchoper © (30.09.02 15:58)
> если пришло меньше 4х считаем ошибку приема, все-равно это
> не дело если пришло меньше!!!


Это конечно перебор. Если заголовок с информацией о длине пакета пришёл не полностью, то надо просто ждать следующего пакета, а имеющийся заголовок скопить, например в буфере заголовока, как я сделал в юните recvpckt

В-общем, обратите внимание на обновлённую версию юнита.


 
VID   (2002-09-30 19:28) [40]

TO POLEVI:

> И что получиться если я пошлю строку с цифирками в начале
> ???


А в чём проблема ?
Посылай на здороье! Только думается мне что ты не обратил внимания на одну функцию, описанную в комментариях юнита:

Function SendTextToSocket(Socket:TCustomWinSocket; Text:String):Integer;
Var S:String;
begin
Result := -1;
IF Text = "" then exit;
IF Socket.Connected then
begin
S:=IntToStr(Length(Text));
Result := Socket.SendText(S+"#"+Text);
end;
end;


ЭТО СТАНДАРТ! БЕЗ ЭТОГО НИКАК!
если жы ты решишь отправить на сервер пакет, не по правилам этой функции, то с сервером ничего страшного не произойдёт, просто пользы от твоего пакеты не будет никакой.
Вроде бы всё логично :)



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

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

Наверх





Память: 0.57 MB
Время: 0.01 c
1-4365
AlexeyMir
2002-11-22 11:31
2002.12.02
Утечка памяти


1-4455
Separator
2002-11-20 11:21
2002.12.02
Бипер на все системах


1-4300
Михич
2002-11-21 09:31
2002.12.02
MDI приложение


1-4350
ЮРИЙ_К
2002-11-21 17:46
2002.12.02
Изменить картинку на закладке PageControl1 по клику


8-4522
GIL
2002-08-11 05:18
2002.12.02
Как очистить TImage





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
Английский Французский Немецкий Итальянский Португальский Русский Испанский