![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Надёжный способ приёма [D6, Win95/98, WinXP]
delpher_gray © (2003-09-17 11:16:00)
Вот заготовка программы:
program PServer;
uses
SysUtils, ScktComp, Windows;
type
TServer = class
private
procedure ClientConnectEvent(Sender: TObject; Socket: TCustomWinSocket);
procedure ClientReadEvent(Sender: TObject; Socket: TCustomWinSocket);
end;
var
hMutex: THandle;
ServerClass: TServer;
ServerSocket1: TServerSocket;
Msg: TMSG;
Cancel: boolean;
procedure TServer.ClientConnectEvent(Sender: TObject; Socket: TCustomWinSocket);
begin
// CODE
end;
procedure TServer.ClientReadEvent(Sender: TObject; Socket: TCustomWinSocket);
begin
// CODE
end;
begin
hMutex := CreateMutex(nil, false, "Server");
if WaitForSingleObject(hMutex, 0) <> wait_TimeOut then
begin
ServerSocket1 := TServerSocket.Create(nil);
ServerSocket1.ServerType := stNonBlocking;
ServerSocket1.Port := 1379;
try
ServerSocket1.Open;
except
Cancel := true;
end;
while not Cancel do
begin
while PeekMessage(Msg, 0, 0, 0, PM_REMOVE) do
begin
TranslateMessage(Msg);
DispatchMessage(Msg);
end;
Sleep(5);
end;
ServerSocket1.Close;
ServerSocket1.Free;
end;
end.
Подскажите как я могу принимать от клиента команды надёжным путём ? Команды могут быть разные...
например команда выключения монитора, или список файлов на диске...
Verg (2003-09-19 13:19:00) [1]
> А можно конкретный пример работы OnWrite ?
См. исходники
function TCustomWinSocket.SendStream(AStream: TStream): Boolean;
C:\Program Files\Borland\Delphi6\Source\Vcl\ScktComp.pas
Вникните.
Потом могу дать вот такие два куска:
function TBridge.SendData(var Buffer; Size : integer):integer;
var Bptr : pChar;
Sends : integer;
S : string;
begin
BPtr := pchar(@Buffer);
Result:=1; Sends:=0;
if Pending="" then
begin
while (Result>0) and (Sends<Size) do
begin
result:=ClientSocket1.Socket.SendBuf((Bptr+Sends)^,Size-Sends);
if Result>=0 then inc(Sends,Result);
end;
if Result=SOCKET_ERROR then
begin
if WSAGetLastError=WSAEWOULDBLOCK then
SetString(Pending, Bptr+Sends, Size-Sends);
end else begin result:=Sends; Pending:=""; end;
end else
begin
SetString(S, Bptr, Size);
Pending:=Pending+S;
Result:=0;
end;
end;
procedure TBridge.ClientSocket1Write(Sender: TObject;
Socket: TCustomWinSocket);
var S : string;
begin
if Pending<>"" then
begin
S:=Pending;
Pending:="";
SendData(Pchar(@S[1])^, length(S));
end;
end;
delpher_gray (2003-09-19 12:13:00) [2]
А можно конкретный пример работы OnWrite ?
Verg (2003-09-19 11:41:00) [3]
> Видно глюки из-за события OnWrite...
Бывает.
Народ вообще почему-то считает это событие каким-то ненужным, лишним что ли....
Между тем, начинать чего либо передавать в сокет после коннекта можно по только по условиям:
Для сервера : OnClientConnect && OnAccept && OnClientWrite
Для клиента : OnConnect && OnWrite
Мало того, при передаче данных (sendbuf) нужно анализировать рез-ат этой функции и если она вернула SOCKET_ERROR, а WSAGETLASTERROR = WSAEWOUDBLOCK, эту порцию информации надо сохранить и передавать только по наступлению следующего OnWrite.
А то напишут в OnConnect-е
Socket.SendText(S1);
Socket.SendText(S2);
Socket.SendText(S3);
Socket.SendText(S4);
Socket.SendText(S5);
.......
Socket.SendText(Sn);
А протом спрашивают: Почему глючит?
Тем не менее
functionTCustomWinSocket.SendText(const s: string): Integer;
begin
Result:= SendBuf(Pointer(S)^, Length(S));
end;
Получается сразу две ошибки!
delpher_gray (2003-09-19 11:40:00) [4]
OnWrite тут по моему ни причём, ведь это событие возникает сразу после соединения, и только один раз за весь сеанс соединения !!
А я перед передачей MemoryStream"а, передавал и текстовые команды и они работали....
delpher_gray (2003-09-19 11:13:00) [5]
Ммммм да....
Видно глюки из-за события OnWrite...
Я толком так и не понял как с ним мозно передать файл со 100% гарантией :)
Slym (2003-09-19 10:06:00) [6]
А вообще как телнет работает... скока сказали принять столько и примет... все остальное ошибки юзера!
Slym (2003-09-19 10:05:00) [7]
Ну если боишься файл не докачать...
Делай типа как в POP3/smtp, там конец письма #13#10+"."+#13#10
UPLOAD file="c:\autoexec.bat";eof="#13#10.#13#10"
качай файл пока не встретишь комбинацию eof...
если файлы бинарные, то надо бы eof генерить для КАЖДОГО файла!
Например GUID,но проверять на вхождение этой строки в файл!
Digitman (2003-09-19 08:32:00) [8]
> Verg
угу ... давно пора)
Verg (2003-09-19 08:15:00) [9]
> при этом не используешь событие OnWrite, то проблемы твои
> именно от этого возникают
Пора бы это в ЧаВо или перед входом в форум-сети повесит :)
Digitman (2003-09-19 08:09:00) [10]
> delpher_gray
с дост.долей уверенности могу предположить, что если ты используешь неблок.режим гнезда на стороне передатчика и если при этом не используешь событие OnWrite, то проблемы твои именно от этого возникают.
Verg (2003-09-19 07:47:00) [11]
> Подскажите как принимать и передавать данные такого типа
> без ошибок !?
Вы что-то себе надумываете.
Какие ошибки имеются ввиду?
Искажения символов? Или exception-ы типа Access violation ?
Против первого типа применяется CRC (контрольная сумма)+Избыточное кодирование (коды Хемминга или Боуза-Чохвингема-Ховисайда, блин, наверняка неправильно всмпомнил) если уж вы прониклись таким недоверием к TCP/IP.
Как тут не вспомнить анекдот про старую деву, свечку и презерватив.
Verg (2003-09-19 07:37:00) [12]
> Плиз подскажите как разделять команды, если использовать
> пример протокола Slym"а ?
Какие проблемы?
В ASCII ориентированных протоколах разделителями обычно является ВКПС (#13#10, \n)
Короче я так ине понял к чему был приведен код программы, при том заведомо неработающей, да еще и свопросом "Как чтобы она надежноработала?"
Для начала сделайте, чтобы она работала хотя бы ненадежно:), а там посмотрим.
$hade (2003-09-19 06:43:00) [13]
Иногда файл не докачивался, иногда в коде файла были ошибки
насколько я знаю - TCP - портокол с гарантированой доставкой пакетов - если ты читаешь 1024 - то 1024 тебе и придет и именно те которые ты посылал...
а если пакеты склеиваются - все таки это ошибки в твоем коде а не в протоколе....
поиши в сети описание протокола ICQ...если убрать всю лишнюю замутность - вполне неплохой протокол...как раз тебе подойдет...
delpher_gray (2003-09-18 20:04:00) [14]
2Digitman:
Насколько я понял, нужно сделать так: от клиента принимать команды типа: "01C:\file.exe"#0 (что означает скачивание файла),
затем сервер посылает команду: "01C:\file.exe"#0"1024"#0 (команда на приём файла, размером 1024 байт).
После такого обмена информацией, клиент переводится в режим приёма файла, и записывает все принятые данные в MemoryStream, пока размер MS не будет равен 1024 байта... Если принялся весь файл, то клинт сохраняет файл, и снова переводится в режим приёма команд...
Правильно так ?
Я раньше использовал метод на подобии этого, и с ним у меня были ошибки ! Иногда файл не докачивался, иногда в коде файла были ошибки, иногда пакеты скелеивались, и клиент не мог отделить файл от команды и т.п. ерунда...
Подскажите как принимать и передавать данные такого типа без ошибок !?
Заранее благодарен.
Digitman (2003-09-18 17:31:00) [15]
> delpher_gray
с протоколом Slym"a тебе придется лексер/парсер реализовывать
дурацкая, думаю, доп.работа ради десятка "языковых" конструкций
кодируй разделы и команды в разделах неким числовым идентификатором строго опред.типа, например, Word
тогда при приеме кодов разделов и команд ты будешь ожидать строго определенное число байт (при Word - 2 байта)
пусть
FILE = 1
CMD = 2
SHELL = 3
пусть
LOAD = 1
UPLOAD = 2
DIR = 3
LIST = 4
тогда на принимающей стороне
case Section of
1: ... речь идет о файловых операциях
2: ... спец.команды
3: ... обращение к оболочке
end;
и т.д. и т.п.
delpher_gray (2003-09-18 16:59:00) [16]
2Verg:
Правильно ! Забыл написать :))
----------
Плиз подскажите как разделять команды, если использовать пример протокола Slym"а ?
Verg (2003-09-18 16:44:00) [17]
> TServer - это класс самого сервера ! Программа консольного
> типа...
Я все понимаю.
Но кто (что) обрабатывает события у ServerSocket1?
Где назначения обработчиков?
Где, в конце концов, ServerClass:=TServer.Create?
Карелин Артем (2003-09-18 14:41:00) [18]
Сигнатуру заведи или передавай файлы в отдельном коннекте.
delpher_gray (2003-09-18 14:22:00) [19]
2Verg:
TServer - это класс самого сервера ! Программа консольного типа...
2Slym:
Пасиба за подсказку !
Но в этом есть такое западло...
Например я послал команду с клиенда этуму серверу типа:
FILE LOAD file="c:\file.zip"#0
Сервер сразу же мне перешлёт файл, а как мне отделить этот файл от других команд ? Как узнать что это именно файл ??
Slym (2003-09-18 05:10:00) [20]
Все упирается в протокол обмена сообщениями!
Сделай типа разделы команд:
FILE
SHELL
CMD
и пр.
а далее подразделы типа:
FILE LOAD
FILE UPLOAD
FILE LIST
FILE DIR
для файл можно использовать например команды ftp протокола...
SHELL EXECUTE
А после команды параметры например с "комма делиметром":
FILE UPLOAD file="c:\autoexec.bat";size=1024
Команду завершай например #13#10 (перевод строки) или #0 (как в пичар)
А далее (для команды FILE UPLOAD file...) сам файл все 1024 байта
FILE LIST directory="c:\";mask="*.*";atrib="FDARSH";style="NSAD"
atrib:File,Dir,Archive,Readonly,Sys,Hiddden
style:Name,Size,Attrib,Date
Отват на команду список файлов с разделителем #13#10 или #0
Если что-то не понятно... бросай это дело