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 - даже не чувствует что к нему подключаются.
Почему??? Как лечить???

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


Verg   (2004-01-13 17:13:00) [1]

Удалено модератором
Примечание: Не бойся, я с тобой... ;)


Verg   (2004-01-13 15:26:00) [2]

Удалено модератором
Примечание: Сори, народ, это уже в чат... ;)


Polevi   (2004-01-13 15:19:00) [3]

Удалено модератором
Примечание: Сори, народ, это уже в чат... ;)


Polevi   (2004-01-13 15:16:00) [4]

извини, чтото переклинило меня, блокирующий конечно


Verg   (2004-01-13 14:49:00) [5]

"может быть все таки НЕблокирующий ?"

Сам попробуй, раз не веришь:

procedure TForm1.Button1Click(Sender: TObject);
var S : TSocket;
   Sa : TSockAddrIn;
   E : integer;
   WData : TWSAData;
   arg : DWORD;
begin
 arg := 1;
 WSAStartUp(WINSOCK_VERSION, WData);
 try
   S := socket(AF_INET, SOCK_STREAM, 0);
   if S = INVALID_SOCKET then exit;

   Fillchar(Sa, sizeof(Sa), 0);
   Sa.sin_family := AF_INET;
   Sa.sin_port := htons(81); // Заранее неверный порт
   Sa.sin_addr.S_addr := inet_addr('213.248.61.208');

// Раскоментарь строки ниже для перевода сокета в неблок. реж.
// и почувствуй разницу
// WSAAsync(Event)Select также переводят сокет в неблок. реж.
// но по умолчанию он инменно блокирующий
//    if ioctlsocket(S, FIONBIO, arg) = SOCKET_ERROR then
//    begin
//      closesocket(S);
//      exit;
//    end;

   E:=connect(S, @Sa, Sizeof(Sa));

   if E = SOCKET_ERROR then
   begin
     E := WSAGetLastError();
     if E <> WSAEWOULDBLOCK then // EWOULDBLOCK в BSD. в WINDOWS зачем-то Билл сказал добавлять приставку WSA
       ShowMessage(IntToStr(WsaGetLastError))
     else
       ShowMessage('Сокет неблокирующий');
   end;
   closesocket(S); //А почему не CloseHandle, интересно? ;-)
 finally
   WSACleanup();
 end;
end;


Может путаешь

Ovelapped attribute

и

nonblocking mode
????


Polevi   (2004-01-13 14:04:00) [6]

>Я тут не понял тогда что ты называешь "асинхронным вводом-выводом". Overlapped IO?

именно, ты правильно перевел :-)

>Сокет, созданный Winsock функцией socket по умолчанию тоже блокирующий, как и принято в BSD.

может быть все таки НЕблокирующий ?


Verg   (2004-01-13 13:42:00) [7]


> Кафедра "Физические методы и приборы контроля" физико-технического
> факультета Уральского государственного технического университета


Отличное заведение, но вот, похоже, что перевод того текста был весьма "вольным" и вступительноу фразу "By default..." перевели как "Как правило...", а не как "По умолчанию...".

Сокет, созданный Winsock функцией socket по умолчанию тоже блокирующий, как и принято в BSD.


Verg   (2004-01-13 13:33:00) [8]


> Polevi ©   (13.01.04 13:12) [26]
> >Verg ©   (13.01.04 12:04) [23]
> согласись что асинхронный режим winsock, да и вообще асинхронный
> ввод вывод win32 очень разнообразен,


Я тут не понял тогда что ты называешь "асинхронным вводом-выводом". Overlapped IO?


> По сути изучая неблокирующий режим winsock надо для начала
> изучить асинхронный ввод-вывод - сообщения, объекты синхронизации


Я бы сказал по-другому:
Изучая работу сокетов, для начала надо изучить неблокирующий режим, а затем уже приступать к изучению "навернутых" на этот режим фич WinAPI, т.е. WinSock, а особенно WinSock2.


Polevi   (2004-01-13 13:18:00) [9]

>Verg ©   (13.01.04 13:08) [25]
а с хелпами все нормально, на msdn все есть


Rouse_   (2004-01-13 13:12:00) [10]

Кафедра "Физические методы и приборы контроля" физико-технического факультета Уральского государственного технического университета

http://gem.dpt.ustu.ru/InterNetBook/API.htm#9.2.2.

И вот только не нужно обьяснять про перевод сокета, сам этим делом занимаюсь не первый год...

Сказано было применительно к сокетам Беркли, а не к их расширению...


Polevi   (2004-01-13 13:12:00) [11]

>Verg ©   (13.01.04 12:04) [23]
согласись что асинхронный режим winsock, да и вообще асинхронный ввод вывод win32 очень разнообразен, и документации от "царя гороха" мягко говоря не адекватны для этой платформы. По сути изучая неблокирующий режим winsock надо для начала изучить асинхронный ввод-вывод - сообщения, объекты синхронизации, Copmletion Routines, APC и тд
хотя должен оговорится что я не знаток unix-платформ, возможно я чегото не знаю относительно них


Verg   (2004-01-13 13:08:00) [12]


> Rouse_ ©   (13.01.04 13:01) [24]


Вот это новость, так новость! :)

Вот уже несколько лет программировал эти самые сокеты и не знал, что перевод сокета в неблокирующий режим - это великое таинство!

Откуда этот бред ты взял?
Я ж говорю, что что-то не то с хелпами.....


Rouse_   (2004-01-13 13:01:00) [13]

> [23] Verg ©   (13.01.04 12:04)

Функции интерфейса сокетов

Блокирующая операция задерживает выполнение программы до окончания своей работы. Как правило, все функции сетевого ввода-вывода сокетов в стиле Беркли – блокирующие. Блокирование проявляется задержкой в выполнении программы до окончания передачи-приема сетевых данных. В табл. 9.4 приведены функции сокетов в стиле Беркли, которые могут блокировать выполнение операций в Winsock API.

Таблица 9.4

Функции в стиле Беркли, которые могут блокировать операции Winsock API

Функция - Описание

accept Подтверждает запрос на установление соединения. Образует новый сокет и соединяет его с удаленным сетевым компьютером, запрашивающим соединение. Исходный сокет возвращается в состояние приема входящих запросов.
closesocket Закрывает одну сторону в соединении сокетов.
connect Устанавливает соединение на указанном сокете.
recv Принимает данные из соединенного сокета.
recvfrom Принимает данные из соединенного или несоединенного сокета.
select Выполняет синхронные мультиплексные операции ввода-вывода путем наблюдения за состоянием нескольких сокетов.
send Передает данные через соединенный сокет.
sendto Передает данные через соединенный или несоединенный сокет.

Изучив описания функций сокетов, приведенные в таблице 9.4, можно заметить, что все они либо производят операции ввода-вывода, либо ждут окончания сетевого ввода-вывода до того, как завершить выполнение. Таким образом, любая функция, связанная с операциями ввода-вывода, может блокировать выполнение остальных функций Winsock API.

С другой стороны, функции, приведенные в таблице 9.5, не выполняют операций ввода-вывода в процессе работы. Они либо преобразуют информацию, либо имеют дело с локальным сокетом сетевого компьютера, т.к. их деятельность не связана с удаленными сетевыми устройствами. Поэтому, несмотря на то, что они также являются функциями в стиле Беркли, ни одна из них не блокирует операции прикладной программы.

Таблица 9.5

Функции в стиле Беркли, не блокирующие работу Winsock API

Функция Описание
bind Присваивает имя неинициализированному (новому) сокету.
getpeername Получает имя удаленного процесса, связанного с указанным сокетом. (Winsock хранит эту информацию в локальной структуре данных, поэтому вызов данной функции не связан с операциями сетевого ввода-вывода.)
getsockname Возвращает имя местного (локального) сокета.
getsockopt Возвращает статус (опции) указанного сокета.
htonl Преобразует порядок байтов в 32-разрядном числе из машиннозависимого в сетевой.
htons Преобразует порядок байтов в 16-разрядном числе из машиннозависимого в сетевой.
inet_addr Преобразует строку с IP-адресом в формате десятичное с точкой в 32-разрядное двоичное число (с сетевым порядком байтов).
inet_ntoa Преобразует IP–адрес в формат десятичное с точкой.
ioctlsocket Управляет параметрами сокета, относящимися к обработке операций сетевого ввода-вывода.
listen Переводит указанный сокет в состояние прослушивания запросов на входное соединение. (Функция переводит сокет в режим прослушивания, однако сама по себе не производит никаких операций сетевого ввода-вывода.)
ntohl Преобразует порядок байтов 32-разрядного числа из сетевого в машиннозависимый (порядок хоста).
ntohs Преобразует порядок байтов 16-разрядного числа из сетевого в машиннозависимый (порядок хоста).
setsockopt Устанавливает режим (опции) работы сокета.
shutdown Закрывает одну сторону дуплексного соединения (только для местного компьютера).
socket Образует точку сетевого соединения и возвращает дескриптор сокета.


Verg   (2004-01-13 12:04:00) [14]


> Polevi ©   (13.01.04 11:51) [22]
> мы говорим об асинхронном режиме, боюсь Беркли тут не поможет


Не бойся, поможет. Достаточно поиграться с функцией

int select(
 int nfds,                          
 fd_set FAR *readfds,              
  fd_set FAR *writefds,              
 fd_set FAR *exceptfds,            
 const struct timeval FAR *timeout  
);

Логика событий FD_WRITE точно та же!

А неблокирующий режим сокета известен со времен "царя гороха".

int nb = 1;
ioctlsocket(s, FIONBIO, &nb);


Polevi   (2004-01-13 11:51:00) [15]

мы говорим об асинхронном режиме, боюсь Беркли тут не поможет


Verg   (2004-01-13 11:22:00) [16]


> Ребят, ну разве так сложно простейший хелп почитать?


Ты знаешь, видимо с этими хелпами что-то не так, раз народ делает столько ошибок около записи в сокет... И вопрос этот уже стал одним из самых популярных на местной конфе по сетям.
Конечно, я думаю, что и borland погорячился со своим названием ф-ций sendtext/receivetext, подкупая и вводя в заблуждения своей кажущейся простотой.
Короче, прани, почитайте Стивенса, например, (царство ему небесное), ведь в конце концов, TCP/IP ядро Windows на 90% Беркли совместимое. Многое взято и от Линуса Торвальдса, много чего добвлено полезного для поддержки многопоточности, но корни - это Беркли.


Verg   (2004-01-13 10:57:00) [17]


> Polevi ©   (08.01.04 19:56) [18]
> >Verg ©   (08.01.04 18:13) [17]
> нет смысла разносить запись в 2 места - если нет ошибки
> то туда а если есть то сюда.. надо помещать данные в список
> и явно вызывать OnWrite обработчик, а OnWrite выбирать их
> оттуда и пытаться отправить..


Это как кому больше нравится.
По крайней мере я не призывал к "разнесению". Те или иные реализации просто должны обязательно учитывать упомянутые мною факты.


> ты пишешь в OnRead - это неправильно, то что у тебя работает
> (возможно ) на локальной машине - в сети работать не будет


Ты пишешь "неправильно ... работать не будет" - это тоже неправильно, суть-то не в том "где", а в том, что "когда".


Rouse_   (2004-01-08 22:11:00) [18]

> [18] Polevi ©   (08.01.04 19:56)
Я б сказал: Я рыдаль ;)

Ребят, ну разве так сложно простейший хелп почитать?
У вас же нет серьезных вопросов которых бы он не разрешил...


Polevi   (2004-01-08 19:56:00) [19]

>Verg ©   (08.01.04 18:13) [17]
нет смысла разносить запись в 2 места - если нет ошибки то туда а если есть то сюда.. надо помещать данные в список и явно вызывать OnWrite обработчик, а OnWrite выбирать их оттуда и пытаться отправить..
у автора OnWrite вообще не используется и он настойчиво продолжает утверждать что все у него хорошо..

"Для себя первую часть вопроса на данный момент считаю ЗАКРЫТОЙ."
- я плакаль :-)


Verg   (2004-01-08 18:13:00) [20]


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


Первая запись в сокет после соединения должна произойти не раньше, чем первый OnWrite - это да.
Но далее записывать в сокет можно и в OnRead. Между прочим OnRead не может наступить раньше, чем первый OnWrite...

Другое дело, что при записи надо обязательно контролировать результат операции и в случае ошибки WSAEWOULDBLOCK продолжать передавать ТОЛЬКО после наступления OnWrite, иначе send... будет упрямо возварщать эту же ошибку.
С другой стороны, если после очередной записи в сокет такой ошибки не возникло, то и события OnWrite тоже не будет.


Страницы:   1 2

Наверх

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