Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2002.12.02;
Скачать: CL | DM;

Вниз

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

 
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.62 MB
Время: 0.017 c
1-4267
Corte ™
2002-11-19 16:32
2002.12.02
Как открыть TreeView root


1-4330
Nicko
2002-11-21 13:43
2002.12.02
Прилипание


1-4450
skirdov
2002-11-20 12:05
2002.12.02
Проблемы при удалении Item из ListView


3-4227
ton2
2002-11-14 12:07
2002.12.02
Написание компонент и TDataLink


1-4321
DN
2002-11-21 17:27
2002.12.02
TIniFile