Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Web сервер. [D5, Win95/98]


Страницы:   1 2

Qwert622 ©   (2004-01-05 16:06:00) 

Есть небольшой пример позаимствованный из сети.
Пример представляет собой web-сервер на основе TServerSocket.
Порт - ServerSocket.Port:=80;
Отрабатывает только GET.
=========
procedure TForm1.WWW_SSClientRead(Sender:TObject; Socket:TCustomWinSocket);
var st:string;
begin
 try
 if Socket.Connected=true then st:=Socket.ReceiveText;
 st:=Copy(st,Pos('/',st),Pos(' HTTP/',st)-Pos('/',st));
 ExecuteQuery(st,Socket);
 Socket.Close;
 except
   try
   if Socket.Connected=true then Socket.Close;
   except
   Exit;
   end;
 end;
end;

procedure TForm1.ExecuteQuery(AQuery:string; Socket:TCustomWinSocket);
var FlName,Params:string;
   FlStream:TFileStream;
   Fl:file of byte;
   FlSize:string;
begin
if not Socket.Connected then exit;
AQuery:=trim(AQuery);
Params:='';
FlName:='';
if pos('?',AQuery)>0 then begin
  Params:=trim(copy(AQuery,pos('?',AQuery)+1,length(AQuery)));
  delete(AQuery,pos('?',AQuery),length(AQuery));
  end;
FlName:=trim(AQuery);
if FlName='/' then FlName:=FlName+WWWDefPage;
FlName:=WWWRoot+FlName;
if FileExists(FlName)=true then begin
  AssignFile(Fl,FlName); Reset(Fl);
  FlSize:=trim(inttostr(FileSize(Fl)));
  Closefile(Fl);
  Socket.SendText('HTTP/1.0 200 OK'+#$0D+#$0A);
  Socket.SendText('Content-Length: '+FlSize+#$0A);
  Socket.SendText('Server: WWW_SS'+#$0A);
  Socket.SendText(#$0D+#$0A);
  FlStream:=TFileStream.Create(FlName,fmOpenRead);
  FlStream.Position:=0;
    try
    Socket.SendStream(FlStream);
    finally
    Memo1.Lines.Add('Файл передан.');
    end;
  end
  else begin
       Socket.SendText('HTTP/1.0 404 Not Found'+#$0D+#$0A);
       Socket.SendText('Server: WWW_SS'+#$0A);
       Socket.SendText(#$0D+#$0A);
       Memo1.Lines.Add('Файл не найден.');
       end;
end;
=========
А теперь вопросы по этому примеру:
1. При передачи картинки (jpg, bmp) по запросу штатного виндувсового IE 6.0 часто (но не всегда!?) эксплорер получает только часть картинки. При этом html файлы передаются всегда нормально (целиком).
Почему??? Как лечить???
2. Принципиально не хочет работать если IE соединяется с сетью через прокси-сервер. Т.е TServerSocket - даже не чувствует что к нему подключаются.
Почему??? Как лечить???

Заранее спасибо всем кто ответит. По возможности с примером.


Polevi   (2004-01-08 18:00:00) [21]

>Qwert622   (08.01.04 17:31) [14]
еще раз повторяю, писать в сокет в асинхронном режиме можно только в событии OnWrite, ты пишешь в OnRead - это неправильно, то что у тебя работает (возможно ) на локальной машине - в сети работать не будет


Verg   (2004-01-08 17:56:00) [22]

function FileTypeToMimeType(const Ft : string):string;
begin
 result:='';
 with TRegistry.Create do
 try
   RootKey:=HKEY_CLASSES_ROOT;
   if OpenKey(ExtractFileExt(Ft), false) then
   try
     Result:=ReadString('Content Type')
   except
     result:=MimeTypes.Values[ExtractFileExt(Ft)];
   end else result:=MimeTypes.Values[ExtractFileExt(Ft)];
 finally
   Free;
   if Result='' then result:='text/plain';
 end;
end;


> if FileExists(FlName)=true then begin
>   FlStream:=TFileStream.Create(FlName,fmOpenRead);
>   Socket.SendText('HTTP/1.0 200 OK'+#$0D+#$0A+
Content-Length: '+IntToStr(FlStream.Size)+#$0D+#$0A+
Server: WWW_SS'+#$0D+#$0A+
'Content-Type: '+FileTypeToMimeType(FlName)+#13#10+
#$0D+#$0A);
>     try
>     Socket.SendStreamThenDrop(FlStream);
>     Memo1.Lines.Add('Передача файла успешно началась...');
>     except
>     Memo1.Lines.Add('Обшибочка');
>     end;
>   end


Сокет при этом вручную не закрывать!!!


Qwert622   (2004-01-08 17:31:00) [23]

Polevi ©   (08.01.04 15:36) [13]
Приведенный пример с исправлением [11] работает. Это проверено.
При присоединение IE НЕ через прокси проблемы не возникают;
html-ки с картинками размещенные на таком сервере загружаются корректно.
Для себя первую часть вопроса на данный момент считаю ЗАКРЫТОЙ.


Polevi   (2004-01-08 15:36:00) [24]

ибо все равно в результате будет вызван winsock.send, который вернет WSAEWOULDBLOCK


Polevi   (2004-01-08 15:32:00) [25]

Qwert622   (08.01.04 15:14) [11]
приведенный тобой пример с SendBuf тоже не будет работать, не вводи народ в заблуждение


Qwert622   (2004-01-08 15:14:00) [26]

Благодарю всех принявших участие в обсуждении.
Ответ на первую часть вопроса такой:
в приведенном примере нужно для передачи файла вместо Socket.SendStream(... использовать Socket.SendBuf(... . Тогда глюк с приемом картинки в IE в рваном виде пропадает.

Пока остается открытой вторая часть вопроса:
Почему при работе IE через прокси вообще не происходит соединения с ServerSocket.
Т.е процедура TForm1.WWW_SSClientConnect не срабатывает при попытке соединения.


Ole   (2004-01-06 13:33:00) [27]

По поводу неполной картинки - тоже был косяк:
Надо правильно заполнить заголовок HTTP. Указать MIME тип и размер!
Content type
Content length и тп
А в конце каждой строки CRLF а не тока LF


Polevi   (2004-01-05 19:26:00) [28]

ну ладно, я сегодня добрый
проблема твоя в том, что метод SendStream не отправялет твой поток целиком, ибо не может этого сделать
вот тебе тестовый пример



unit Unit1;

interface

uses
 Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
 Dialogs, ScktComp;

type
 TForm1 = class(TForm)
   cs: TClientSocket;
   ss: TServerSocket;
   procedure csWrite(Sender: TObject;
     Socket: TCustomWinSocket);
   procedure FormCreate(Sender: TObject);
 private
   { Private declarations }
 public
   { Public declarations }
 end;

var
 Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
 ss.Port:=6666;
 ss.Active:=true;
 cs.Address:='127.0.0.1';
 cs.Port:=6666;
 cs.Active:=true;
end;

procedure TForm1.csWrite(Sender: TObject;
 Socket: TCustomWinSocket);
var
 fs:TFileStream;
begin
 fs:=TFileStream.Create('c:\bigfile.exe',fmOpenRead);
 if not Socket.SendStream(fs) then
   beep;
 Caption:=IntToStr(fs.Position);
end;

end.



метод SendStream возвратит управление отправив только часть потока, и вот почему

кусок исходников от Борладна



function TCustomWinSocket.SendStreamPiece: Boolean;
....

         AmountSent := send(FSocket, Buffer, AmountInBuf, 0);
         if AmountSent = SOCKET_ERROR then
         begin
           ErrorCode := WSAGetLastError;
           if ErrorCode <> WSAEWOULDBLOCK then
           begin
             Error(Self, eeSend, ErrorCode);
             Disconnect(FSocket);
             DropStream;
             if FAsyncStyles <> [] then Abort;
             Break;
           end else
           begin
             FSendStream.Position := StartPos;
              Break;
           end;
...
end;



вызов winsock ф-ии send для неблокируещего сокета привел к ошибке  WSAEWOULDBLOCK, что означает "буфер приемник переполнен, я сообщу тебе когда он будет готов принять следующую порцию данных событием FD_WRITE" и ф-ия SendStream возвратила управление, отправив только часть потока


Qwert622   (2004-01-05 18:35:00) [29]

Для FireMan_Alexey.
Я наверное не очень хорошо сформулировал вопрос (вернее 2 вопроса).
1."Сервер" корректно получает получает запрос от IE, корректно обрабатывает его, находит запрашиваемый файл, отправляет его эксплореру (Socket.SendStream(FlStream);), НО эксплорер (кстати и NetVampire) получает только ЧАСТЬ файла.
Как я понимаю это связано с тем что посылаемый сервером поток при передаче может быть (а может и не быть) разорван на несколько частей. И експлореру нужно как то объяснить что эти части нужно сшивать. А вот как - этого я пока и не понял.
2. При работе IE через прокси вообще не происходит соединения с ServerSocket - и это есть отдельный вопрос.

По поводу "if Socket.Connected=true then st:=Socket.ReceiveText;" - да Вы правы. Эта строка не нужна но и помешать работе она не может.


FireMan_Alexey   (2004-01-05 18:14:00) [30]

Дело в том, что при возникновении Read в буфере может оказаться
и 1 байт, а не строка!
По этому обрабатывать запрос експлорера нужно проверяя
строку на символы #13#10, повторяющиеся 2 раза. Это, как я понял,
отделяет загаловок от последующих данных. Т.к. при посылке дву строк за короткий промежуток времени "Привет", а затем " Мир" сервер получит "Привет Мир" или может "Приве" и "т Мир". Т.е. нет уверенности в том, что ты получил нужные данные!
1) Зачем это!? if Socket.Connected=true then st:=Socket.ReceiveText;
Если возникает Чтение значит сокет существует и он открыт!
2) Еще вопрос, а не проще в неблок режиме?


Polevi   (2004-01-05 18:14:00) [31]

конкретно почитай хелп на ф-ию WSAAsyncSelect


Polevi   (2004-01-05 18:05:00) [32]

Удалено модератором
Примечание: Разборки в чате устраиваем ...


Qwert622   (2004-01-05 18:02:00) [33]

Удалено модератором
Примечание: Разборки в чате устраиваем ...


Polevi   (2004-01-05 17:46:00) [34]

чтобы встретить указания надо читать документацию, вот и займись этим


Qwert622   (2004-01-05 17:13:00) [35]

1. Для простоты считаем что уверенность есть.
При работе IE не через прокси - в буфере оказывается не рваный запрос. А при работе IE через прокси - в буфере вообще ничего не оказывается поскольку не происходит WWW_SSClientConnect. К серверу никто не присоединяется.
2. То что было послано от сервера к IE посредством SendText - компьютер с експлорером получает. (Это проверялось в NetVempire - он показывает протокол обмена клиент-сервер).
3. Я не встречал указаний на то, что нельзя писать в сокет данные в обработчике ClientRead. Тем более что данные пишутся. Почему-то только не всегда целиком (или не целиком читаются IE ?).
4. Это само собой. А всетаки возвращаясь к вопросу ...


Polevi   (2004-01-05 16:43:00) [36]

откуда уверенность в том что на момент вызова ReceiveText в буфере гнезда будет находится запрос целиком, а не его чаcть ?
где анализ результата SendText ?
почему ты пишешь в сокет данные в обработчике ClientRead, в нем можно только читать, для записи предназначено событие ClientWrite
тебе нужно почитать про асинхронный режим winsock, иначе ничего у тебя путного не выйдет
или работай в блокирующем режиме


Страницы:   1 2

Наверх

Титульная страница Поиск, карта сайта Написать письмо