Текущий архив: 2002.12.02;
Скачать: CL | DM;
Вниз
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;
ЭТО СТАНДАРТ! БЕЗ ЭТОГО НИКАК!
если жы ты решишь отправить на сервер пакет, не по правилам этой функции, то с сервером ничего страшного не произойдёт, просто пользы от твоего пакеты не будет никакой.
Вроде бы всё логично :)
← →
Polevi © (2002-09-30 20:33) [41]2VID © (30.09.02 19:28)
да, не обратил внимания, сорри :-)
← →
Subfire © (2002-09-30 20:37) [42]VID © ^) Все...я уже сказал что ошибся...я говорил об откправке пакета =<256 байт...
А по поводу спецификации и отправки...
Дело в том что на уровне протокола идет фрагментация, т.е. в сеть отправляется за раз не столько байт, сколько ты передал TSocket а столько, какой у сети MTU...
Потому ты и получаещь в 8килов за раз а не все 16...
А в принципе по спецификации MIN=576 и MAX=65535
← →
SemFLY © (2002-09-30 23:56) [43]Всем Большое Спасибо, что так много предложений и решений моей задачи... ;))
Пока сделал так :
Reg.GetValueNames(Val); // читаем все значения ключа
for I := 0 to Val.Count - 1 do
begin // упаковываем значения в RegList и разделяем их построчно #13#10
RegList := RegList + Val.Strings[I]+" -> "+Reg.ReadString(Val.Strings[I])+#13#10;
end; ServerSocket1.Socket.Connections[0].SendText("#4"+RegList); // отправляем список
- - - - - - - - - - - - - - - - - -
Так всё работает и приходит чисто, без всяких префиксов строки и посторонних символов ;)
← →
VID © (2002-10-01 08:54) [44]to SemFLY:
1. Val.Strings[I] = Val[I];
2. На клиенте/сервере есть решение в случае если пакет придёт по частям, либо каким-нибудь образом придёт "склееный" пакет ?
просто интереса ради, покажи код:
ClientOnRead и ServerOnClientRead
← →
SemFLY © (2002-10-02 01:36) [45]ClientOnRead:
procedure TForm1.ClientSocket1Read(Sender: TObject;
Socket: TCustomWinSocket);
var
RecText, MsgTF : String;
MyList : TStringList;
begin
RecText := "";
RecText := ClientSocket1.Socket.ReceiveText;
MsgTF := Copy(RecText,1,2);
If MsgTF = "#1" then
begin
Delete(RecText,1,2);
MyList := TStringList.Create;
MyList.Text := RecText;
Memo1.Lines.AddStrings(MyList);
MyList.Clear;
RecText := "";
end;
end;
← →
Subfire © (2002-10-02 01:54) [46]SemFLY ©
Мндя...прости, за нашим разговором мы забыли с чего все началось :)))
Я тебе советую сделать так:
Сначала подготовить список файло, поместить его в TStrings
...
var FilesList:TStrings
...
FileList:=TStringList.Create;
Repeat
...
FileList.Add(Filename); //Заполняем именами файлов
...
Затем отправить СРАЗУ весь список:
...
ClientSocket.Socket.SendBuf(FileList,SizeOf(FileList));
...
При получении
...
procedure TForm1.ServerSocketClientRead(Sender: TObject;
Socket: TCustomWinSocket);
FileList:=TStringList.Create;
var FilesList:TStrings
begin
TempStr:=TStringList.Create;
Socket.ReceiveBuf(FilesList,Socket.ReceiveLength);
ListBox1.Items.Assign(FilesList);
end;
....
И весь список попадает в компонент ListBox1
Дешево и сердито, и никаких разделителей самому писать не надо..
Единственно на что нужно обратить внимание - это на то о чем мы говорили в том случае, если у тебя большой список файлов, то он может не влезть в один пакет, и событие ClientRead будет вызвано несколько раз, с разными частями общего списка. Если этим пренебречь - ты получишь только кусок списка - концовку...хорошо если это вообще будет корректный кусок данных :))) На практике, у меня самый маленький пакет был 4Кб. Так что если список заведомо меньше - забудь все что я сказал...
Иначе - используй мою или VIDA процедуру обработки больших данных...Свой вариант - скоро выложу.
← →
VID © (2002-10-02 02:06) [47]Вот именно поэтому я и попросил SemFLY выложить код принятия пакета на сервере/клиенте :)
В ОБЩЕМ:
> Иначе - используй мою или VIDA процедуру обработки больших
> данных...Свой вариант - скоро выложу.
ЭТО ГЛАВНОЕ. А вообще можешь использовать метод предложенный SubRife"ом, либо :
Client.SOcket.SendText(FileList.Text);
{Хотя если на приёмнике пакет будет обрабатываться с помощью функций из юнита recvpckt, для отправки надо будет обязательно использовать функцию SendTextToSocket описанную в комментариях этого юнита}
← →
Subfire © (2002-10-02 14:14) [48]Ну вот и мой метод:
о его достоинствах читайте прямо на сайте :)
http://delphibase.endimus.com/?action=viewfunc&topic=nettransfer&id=10336
VID © честно говоря сравнивал и тестировал наши методы...
Написал тестирующий модул по такому алгоритму:
создаем SendText,RecvText : TStrings. Задаем число отправляемых строк. Заполняем SendText заданным числом строк со случайным размером и случайными символами. Запускаем отдельный поток и посылаем построчно используя твой SendTextToSocket...
Одновременно идет прием данных с использованием твоего кода и заполняем RecvText. И построчно сравниваем SendText,RecvText.
Причем я использую отравку 100 строк блоков размером 1-16000
Так вот, почему-то если я используб твою процедуру, то при большом размере строк я получаю почему-то в RecvText не все 100 строк а меньше...
Почему - не знаю. Мой код тест проходит. Собоственно я на этом тесте и отлавливал всех своих блок :))
Может я конечно и где-то ошибаюсь и с твоим кодом все ОК...Пока не знаю...
Если хочешь - могу прислать полный текст теста.
← →
SemFLY © (2002-10-02 14:46) [49]Всё понял ! ;)
Спасибо огромное VID и Subfire, мне можно сказать в свою прогу тока сунуть код и всё готово ;)))
Всё разложили по полочкам... ;))
- - - - - - - - -
P.S. Ещё вопрос у меня есть, как лучше сделать авторизация пользователя на сервере, каким методом и в каком виде лучше отправлять пароль для его сохранности ?
← →
Subfire © (2002-10-02 15:41) [50]Пароль лучше всего шифровать для того, чтобы сниффер не перехватывал...
Если слышал о алгоритмах DES то используй их...
Если нет, ну что же можно шифровать открытым ключем - в конце концов, ты ведь не сервак для ФСБ делаешь :)))
Впринципе, советую такой алгоритм - есть некоторый открытый ключ Key1 (скажем строка "Secret Key") который изначально зашит и в серваке и в клиенте.
При коннекте, сервак генерируют некоторый ключ Key2 случайным образом, затем шифрует (хэширует) Key2 с использованием key1 и направляет клиенту...
Клиент расшифровывет полученные данные и получает key1.
Затем шифрует введенный пользователем пароль с использованием key2 и отправляет серваку.
Сервак расшифровывет пароль используя key2 и проверяет.
Пароль храниться на серваке в зашифрованном виде.
Вот и все.
Положим, сниффер ловит пароль, шифрованный key2.
Чтобы получить key2 придется сначала словить от сервака key2, который зашифрован key1. Значит, придется исследовать исходный код клиента или сервака, чтобы выцепит key1 (который тоже может храниться в зашифрованном виде :). Затем, придется исследовать алгоритмы хэширования...А если еще у тебя две разные хэш-функции для key1 и key2 это еще более усложняет.
Короче, профессионал разберется, остальные обламываются...что и требовалось...
P.S. Конечно, можно ибойтись без key2 а использовать key1, но чем больше у нас накрученный алгоритм, тем сложнее будет ломать, и мы берем не качеством, а количеством :)))
Если хочешь качеством - нужно использовать алгоритмы с открытыми ключами типа DES.
Схема такая - сервер и клиет генерируют по два ключа каждый - приватный и публичный ключ, т.е. получаем 4 ключа: CliPrivKey,CliPublicKey,ServPrivKey,ServPublicKey.
Причем, публичный ключ функционально зависит от соотв. приватного...
Затем клинт и сервер обмениваются публичными ключами.
Затем, когда клиент посылает мессагу, он про шифровании использует 3 ключа CliPrivKey,CliPublicKey,ServPublicKey.
Сервак расшифровывает используя ServPrivKey,ServPublicKey,CliPublicKey
← →
Subfire © (2002-10-02 16:23) [51]У меня там очепятка:) Жаль нельзя менять свой мессадже!
"Чтобы получить key2 придется сначала словить от сервака key2, который зашифрован key1" следует читать как:
Чтобы получить ПАРОЛЬ придется сначала словить от сервака key2, который зашифрован key1.
← →
VID © (2002-10-02 17:39) [52]To SubFire: пришли пожалуйста исходники тест проекта на vidsnap@mail.ru
← →
SemFLY © (2002-10-02 18:30) [53]Subfire, ok ! :)
А где можно почитать о алгоритмах DES или может скачать компанент для работы с ними ?
P.S. А сниффер никак не обойти, тока один вариант, я так понимаю это шифровать информацию между клиентом и сервером ?
← →
Subfire © (2002-10-02 20:07) [54]Сниффер не обойти.....
Тока нудно повторю, что сниффер может работать в одном сегменте сети с сервером или клиенотм.
← →
VID © (2002-10-03 12:00) [55]TO SubFire:
Я написал подобное твоему тестовое приложение.
Правда в отличие от твоего, я не использовал доп. потоков.
Отправка выпл-ся приложением- клиентов, приём приложением-сервером. Каждый работает только в основном потоке приложения.
Есть список строк, в котором 10 строк, каждая длиной 5000 симв.
Клиент (неблокирующий) отправляет на сервер все эти 10 строк в цикле
VAR SND:TStringList; //Список с 10-ю строками каждая длиной 5000 симв.
for i:=0 to snd.count -1 do sendtexttosocket(client.socket, snd[i]);
Дествительно проблема, описанная тобою имела место быть.
Вместо 10 пакетов сервер принял только два:
А теперь посмотри код принятия пакетов на уровне сервера:
VAR S:String;
RECV:TStringList;
begin
S:=Socket.ReceiveText;
RECV.ADD(S);
end;
В результате в списке RECV ТОЛЬКО 2 СТРОКИ! Заметь, здесь нет ни одного упоминания о функциях из моего юнита. Т.е. Проблема вовсе не в них.
Проблема как раз на уровне передатчика.
Если переключить клиента в блокирующий режим stBlocking то на сервер действительно будут отправлены все 10 строк, иначе если клиент не блокирующий, то отправляется только 2 строки.
Так что мне теперь очень интересно посмотреть твой код:
1. по отправке всех строк списка на сервер + код всех ТВОИХ функций вызываемых из вышеозначенной.
2. по приёму пакетов на сервере.
3. КАКОЙ РЕЖИМ КЛИЕНТА ТЫ ИСПОЛЬЗУЕШЬ ?
← →
Subfire © (2002-10-03 15:31) [56]ОК...я пришлю...
Просто я его привел уже в жуткий вид - тестировал просото еще некоторые способы в разных режимах...
А твоя проблема, которая возникла, как раз была мною решена в самом начале - отдельным потоком. Это просто эмуляция двух приложений обменивающихся данными - иначе, действительно, в одном потоке при блокирующих сокетах некоторые пакеты не обрабатываются а отбрасываются....
С другой стороны, когды ты делаешь неблокирующие сокеты - тоже в одном потоке - тоже возникнет проблемма, т.к. при нормальной работе и при отладке результаты могут не быть идентичны :) На эту граблю я попал, кады отлаживал свой метод....
Кстати счаз его уже использую - плюс в том, что при удалении 3 строк я переделываю процедуру для работу напрямую с WinSock, что мне собственно и надо...
← →
VID © (2002-10-03 20:29) [57]У меня одно приложение-клиент, другое - сервер.
Мне незачем использовать доп. потоки.
Клиент отправляет пакеты серверу.
Если клиент stBlocking ТО ВСЕ ПАКЕТЫ ДОХОДЯТ ДО СЕРВЕРА
Если калиент stNonBlocking то доходят только две строки.
Ещё раз повторяю - функции моего юнита вообще не использую. я даже текст отправляю просто методом Socket.SendText а не с помощью функции SendTextToSocket(). Т.е. я хочу сказать, что условия моего теста равны условиям твоего теста.
А теперь самое интересное:
Сокет - блокирующий (что бы пакеты всё-таки дошли до сервера)
Отправляю функцией SendTextToSocket
Принимаю, так как указано в примере использования моего юнита.
Естественно использую необходимые функции из recvpckt
Создаю список строк каждая строка = 5000 символов.
Отправляю его от проги-клиента к проге-серверу.
Каждую полностью принятую строку сервер заносит в список RECV
РЕЗУЛЬТАТ:
ОТПРАВЛЕНО 10 строк
ПРИНЯТО 10 строк
Какие ещё могут быть вопросы ?
Повторюсь, проблема в клиенте, а не в сервере.
← →
Subfire © (2002-10-03 21:48) [58]Нее...ты :) Не прав :)))
Но хочу обрадовать - все-таки твой код работает!
У меня одно приложение и клиент и сервер - нечего их разносить, это же тест :))))
Просто, судя по всему твой код немного медленнее моего обрабатывается *это не точно - цифры назову позже*, и при небольшой оптимизации процедуры отправки - я получил все отправленные строки нормально.
← →
Subfire © (2002-10-03 22:05) [59]Для SemFly:
Вот тебе простенький (тупой я бы сказал :) шифровальщик:
Для шифровки вызываешь Enrypt, передавая строку для шифрования и параметр Key - типа word - ключ шифровки... Возвращает зашифрованную строку.
Для расшифровки - вызывай Decrypt - передавая ей зашифрованную строку и ТОТ ЖЕ КЛЮЧ!!! Возвращает расшифрованную строку.
АЛГОРИТМ ТУПОЙ, СЛАБЫЙ, прямо как XOR ^) Исходная и конечная строки сходны по размеру...Усе.
unit Unit_EasyEncrypt;
interface
function Encrypt(const S: String; Key: Word): String;
function Decrypt(const S: String; Key: Word): String;
implementation
const
C1 = 52845;
C2 = 22719;
function Encrypt(const S: String; Key: Word): String;
var
I: byte;
ResStr:String;
begin
SetLength(ResStr,Length(S));
ResStr[1] := S[1];
for I := 2 to Length(S) do begin
ResStr[I] := char(byte(S[I]) xor (Key shr 8));
Key := (byte(ResStr[I]) + Key) * C1 + C2;
end;
Result:=ResStr;
end;
function Decrypt(const S: String; Key: Word): String;
var
I: byte;
ResStr:String;
begin
SetLength(ResStr,Length(S));
ResStr[1] := S[1];
for I := 2 to Length(S) do begin
ResStr[I] := char(byte(S[I]) xor (Key shr 8));
Key := (byte(S[I]) + Key) * C1 + C2;
end;
Result:=ResStr;
end;
end.
← →
VID © (2002-10-03 23:19) [60]to SubFire: у меня тоже в одном приложение и клиент и сервер, просто я для пущей верности запустил две копии этого приложения, и использовал одну копию как клиент а другую как сервер :)
а в чём именно я не прав ?
to SemFly: на UBPFD есть функции и один юнит для шифрования/дешифрования.
← →
Subfire © (2002-10-04 00:17) [61]^) Не прав относительно, что проблемма была в клиенте...это была комплексная проблемма.
Теперь все ОК :)))
Вообще-то наши варианты по сути идентичны.
Немного разная реализация.
Моя мне кажется лучше по крайней мере в интерфейсной части - все-таки проще один раз вызвать процедуру, которая все сам сделает, чем писать такой код в OnRead//
А вообще то же, тока в профиль :))))
А вообще приятно было пообщаться с умным человеком.
P.S. теперь буду регулярно навещать ваш проект...
← →
VID © (2002-10-04 10:39) [62]To SubFire:
>А вообще приятно было пообщаться с умным человеком.
Взаимно :)
Только на будущее одно замечание: при отправке кода в UBPFD постарайся выкладывать его в более "Стандартном" виде (например без Form1....), а ещё лучше - прочти правила по оформлению отправляемого когда, там есть...
← →
panov © (2002-10-04 22:40) [63]Мне так и непонятна одна вещь осталась...
>Subfire
Такая строка у тебя никогда не будет работать...
ClientSocket.Socket.SendBuf(FileList,SizeOf(FileList));
SizeOf(FileList) будет 4 всегда.
← →
Rouse_ © (2002-10-05 03:36) [64]мммм дя, вот это раздули веточку ;)
← →
SemFLY © (2002-10-06 11:51) [65]давате дальше...очень интересно ;)
я отсюда много чего для себя нового открыл, хотя казалось бы ничего особо нет...
Страницы: 1 2 вся ветка
Текущий архив: 2002.12.02;
Скачать: CL | DM;
Память: 0.69 MB
Время: 0.026 c