Форум: "Сети";
Текущий архив: 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