Форум: "Сети";
Текущий архив: 2004.03.28;
Скачать: [xml.tar.bz2];
ВнизWeb сервер. Найти похожие ветки
← →
Qwert622 (2004-01-05 16:06) [0]Есть небольшой пример позаимствованный из сети.
Пример представляет собой 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-05 16:43) [1]откуда уверенность в том что на момент вызова ReceiveText в буфере гнезда будет находится запрос целиком, а не его чаcть ?
где анализ результата SendText ?
почему ты пишешь в сокет данные в обработчике ClientRead, в нем можно только читать, для записи предназначено событие ClientWrite
тебе нужно почитать про асинхронный режим winsock, иначе ничего у тебя путного не выйдет
или работай в блокирующем режиме
← →
Qwert622 (2004-01-05 17:13) [2]1. Для простоты считаем что уверенность есть.
При работе IE не через прокси - в буфере оказывается не рваный запрос. А при работе IE через прокси - в буфере вообще ничего не оказывается поскольку не происходит WWW_SSClientConnect. К серверу никто не присоединяется.
2. То что было послано от сервера к IE посредством SendText - компьютер с експлорером получает. (Это проверялось в NetVempire - он показывает протокол обмена клиент-сервер).
3. Я не встречал указаний на то, что нельзя писать в сокет данные в обработчике ClientRead. Тем более что данные пишутся. Почему-то только не всегда целиком (или не целиком читаются IE ?).
4. Это само собой. А всетаки возвращаясь к вопросу ...
← →
Polevi © (2004-01-05 17:46) [3]чтобы встретить указания надо читать документацию, вот и займись этим
← →
Qwert622 (2004-01-05 18:02) [4]Удалено модератором
Примечание: Разборки в чате устраиваем ...
← →
Polevi © (2004-01-05 18:05) [5]Удалено модератором
Примечание: Разборки в чате устраиваем ...
← →
Polevi © (2004-01-05 18:14) [6]конкретно почитай хелп на ф-ию WSAAsyncSelect
← →
FireMan_Alexey © (2004-01-05 18:14) [7]Дело в том, что при возникновении Read в буфере может оказаться
и 1 байт, а не строка!
По этому обрабатывать запрос експлорера нужно проверяя
строку на символы #13#10, повторяющиеся 2 раза. Это, как я понял,
отделяет загаловок от последующих данных. Т.к. при посылке дву строк за короткий промежуток времени "Привет", а затем " Мир" сервер получит "Привет Мир" или может "Приве" и "т Мир". Т.е. нет уверенности в том, что ты получил нужные данные!
1) Зачем это!? if Socket.Connected=true then st:=Socket.ReceiveText;
Если возникает Чтение значит сокет существует и он открыт!
2) Еще вопрос, а не проще в неблок режиме?
← →
Qwert622 (2004-01-05 18:35) [8]Для FireMan_Alexey.
Я наверное не очень хорошо сформулировал вопрос (вернее 2 вопроса).
1."Сервер" корректно получает получает запрос от IE, корректно обрабатывает его, находит запрашиваемый файл, отправляет его эксплореру (Socket.SendStream(FlStream);), НО эксплорер (кстати и NetVampire) получает только ЧАСТЬ файла.
Как я понимаю это связано с тем что посылаемый сервером поток при передаче может быть (а может и не быть) разорван на несколько частей. И експлореру нужно как то объяснить что эти части нужно сшивать. А вот как - этого я пока и не понял.
2. При работе IE через прокси вообще не происходит соединения с ServerSocket - и это есть отдельный вопрос.
По поводу "if Socket.Connected=true then st:=Socket.ReceiveText;" - да Вы правы. Эта строка не нужна но и помешать работе она не может.
← →
Polevi © (2004-01-05 19:26) [9]ну ладно, я сегодня добрый
проблема твоя в том, что метод 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 возвратила управление, отправив только часть потока
← →
Ole (2004-01-06 13:33) [10]По поводу неполной картинки - тоже был косяк:
Надо правильно заполнить заголовок HTTP. Указать MIME тип и размер!
Content type
Content length и тп
А в конце каждой строки CRLF а не тока LF
← →
Qwert622 (2004-01-08 15:14) [11]Благодарю всех принявших участие в обсуждении.
Ответ на первую часть вопроса такой:
в приведенном примере нужно для передачи файла вместо Socket.SendStream(... использовать Socket.SendBuf(... . Тогда глюк с приемом картинки в IE в рваном виде пропадает.
Пока остается открытой вторая часть вопроса:
Почему при работе IE через прокси вообще не происходит соединения с ServerSocket.
Т.е процедура TForm1.WWW_SSClientConnect не срабатывает при попытке соединения.
← →
Polevi © (2004-01-08 15:32) [12]Qwert622 (08.01.04 15:14) [11]
приведенный тобой пример с SendBuf тоже не будет работать, не вводи народ в заблуждение
← →
Polevi © (2004-01-08 15:36) [13]ибо все равно в результате будет вызван winsock.send, который вернет WSAEWOULDBLOCK
← →
Qwert622 (2004-01-08 17:31) [14]Polevi © (08.01.04 15:36) [13]
Приведенный пример с исправлением [11] работает. Это проверено.
При присоединение IE НЕ через прокси проблемы не возникают;
html-ки с картинками размещенные на таком сервере загружаются корректно.
Для себя первую часть вопроса на данный момент считаю ЗАКРЫТОЙ.
← →
Verg © (2004-01-08 17:56) [15]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
Сокет при этом вручную не закрывать!!!
← →
Polevi © (2004-01-08 18:00) [16]>Qwert622 (08.01.04 17:31) [14]
еще раз повторяю, писать в сокет в асинхронном режиме можно только в событии OnWrite, ты пишешь в OnRead - это неправильно, то что у тебя работает (возможно ) на локальной машине - в сети работать не будет
← →
Verg © (2004-01-08 18:13) [17]
> Polevi © (08.01.04 18:00) [16]
> >Qwert622 (08.01.04 17:31) [14]
> еще раз повторяю, писать в сокет в асинхронном режиме можно
> только в событии OnWrite, ты пишешь в OnRead - это неправильно,
> то что у тебя работает (возможно ) на локальной машине -
> в сети работать не будет
Первая запись в сокет после соединения должна произойти не раньше, чем первый OnWrite - это да.
Но далее записывать в сокет можно и в OnRead. Между прочим OnRead не может наступить раньше, чем первый OnWrite...
Другое дело, что при записи надо обязательно контролировать результат операции и в случае ошибки WSAEWOULDBLOCK продолжать передавать ТОЛЬКО после наступления OnWrite, иначе send... будет упрямо возварщать эту же ошибку.
С другой стороны, если после очередной записи в сокет такой ошибки не возникло, то и события OnWrite тоже не будет.
← →
Polevi © (2004-01-08 19:56) [18]>Verg © (08.01.04 18:13) [17]
нет смысла разносить запись в 2 места - если нет ошибки то туда а если есть то сюда.. надо помещать данные в список и явно вызывать OnWrite обработчик, а OnWrite выбирать их оттуда и пытаться отправить..
у автора OnWrite вообще не используется и он настойчиво продолжает утверждать что все у него хорошо..
"Для себя первую часть вопроса на данный момент считаю ЗАКРЫТОЙ."
- я плакаль :-)
← →
Rouse_ © (2004-01-08 22:11) [19]> [18] Polevi © (08.01.04 19:56)
Я б сказал: Я рыдаль ;)
Ребят, ну разве так сложно простейший хелп почитать?
У вас же нет серьезных вопросов которых бы он не разрешил...
← →
Verg © (2004-01-13 10:57) [20]
> Polevi © (08.01.04 19:56) [18]
> >Verg © (08.01.04 18:13) [17]
> нет смысла разносить запись в 2 места - если нет ошибки
> то туда а если есть то сюда.. надо помещать данные в список
> и явно вызывать OnWrite обработчик, а OnWrite выбирать их
> оттуда и пытаться отправить..
Это как кому больше нравится.
По крайней мере я не призывал к "разнесению". Те или иные реализации просто должны обязательно учитывать упомянутые мною факты.
> ты пишешь в OnRead - это неправильно, то что у тебя работает
> (возможно ) на локальной машине - в сети работать не будет
Ты пишешь "неправильно ... работать не будет" - это тоже неправильно, суть-то не в том "где", а в том, что "когда".
← →
Verg © (2004-01-13 11:22) [21]
> Ребят, ну разве так сложно простейший хелп почитать?
Ты знаешь, видимо с этими хелпами что-то не так, раз народ делает столько ошибок около записи в сокет... И вопрос этот уже стал одним из самых популярных на местной конфе по сетям.
Конечно, я думаю, что и borland погорячился со своим названием ф-ций sendtext/receivetext, подкупая и вводя в заблуждения своей кажущейся простотой.
Короче, прани, почитайте Стивенса, например, (царство ему небесное), ведь в конце концов, TCP/IP ядро Windows на 90% Беркли совместимое. Многое взято и от Линуса Торвальдса, много чего добвлено полезного для поддержки многопоточности, но корни - это Беркли.
← →
Polevi © (2004-01-13 11:51) [22]мы говорим об асинхронном режиме, боюсь Беркли тут не поможет
← →
Verg © (2004-01-13 12:04) [23]
> 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);
← →
Rouse_ © (2004-01-13 13:01) [24]> [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 13:08) [25]
> Rouse_ © (13.01.04 13:01) [24]
Вот это новость, так новость! :)
Вот уже несколько лет программировал эти самые сокеты и не знал, что перевод сокета в неблокирующий режим - это великое таинство!
Откуда этот бред ты взял?
Я ж говорю, что что-то не то с хелпами.....
← →
Polevi © (2004-01-13 13:12) [26]>Verg © (13.01.04 12:04) [23]
согласись что асинхронный режим winsock, да и вообще асинхронный ввод вывод win32 очень разнообразен, и документации от "царя гороха" мягко говоря не адекватны для этой платформы. По сути изучая неблокирующий режим winsock надо для начала изучить асинхронный ввод-вывод - сообщения, объекты синхронизации, Copmletion Routines, APC и тд
хотя должен оговорится что я не знаток unix-платформ, возможно я чегото не знаю относительно них
← →
Rouse_ © (2004-01-13 13:12) [27]Кафедра "Физические методы и приборы контроля" физико-технического факультета Уральского государственного технического университета
http://gem.dpt.ustu.ru/InterNetBook/API.htm#9.2.2.
И вот только не нужно обьяснять про перевод сокета, сам этим делом занимаюсь не первый год...
Сказано было применительно к сокетам Беркли, а не к их расширению...
← →
Polevi © (2004-01-13 13:18) [28]>Verg © (13.01.04 13:08) [25]
а с хелпами все нормально, на msdn все есть
← →
Verg © (2004-01-13 13:33) [29]
> Polevi © (13.01.04 13:12) [26]
> >Verg © (13.01.04 12:04) [23]
> согласись что асинхронный режим winsock, да и вообще асинхронный
> ввод вывод win32 очень разнообразен,
Я тут не понял тогда что ты называешь "асинхронным вводом-выводом". Overlapped IO?
> По сути изучая неблокирующий режим winsock надо для начала
> изучить асинхронный ввод-вывод - сообщения, объекты синхронизации
Я бы сказал по-другому:
Изучая работу сокетов, для начала надо изучить неблокирующий режим, а затем уже приступать к изучению "навернутых" на этот режим фич WinAPI, т.е. WinSock, а особенно WinSock2.
← →
Verg © (2004-01-13 13:42) [30]
> Кафедра "Физические методы и приборы контроля" физико-технического
> факультета Уральского государственного технического университета
Отличное заведение, но вот, похоже, что перевод того текста был весьма "вольным" и вступительноу фразу "By default..." перевели как "Как правило...", а не как "По умолчанию...".
Сокет, созданный Winsock функцией socket по умолчанию тоже блокирующий, как и принято в BSD.
← →
Polevi © (2004-01-13 14:04) [31]>Я тут не понял тогда что ты называешь "асинхронным вводом-выводом". Overlapped IO?
именно, ты правильно перевел :-)
>Сокет, созданный Winsock функцией socket по умолчанию тоже блокирующий, как и принято в BSD.
может быть все таки НЕблокирующий ?
← →
Verg © (2004-01-13 14:49) [32]"может быть все таки НЕблокирующий ?"
Сам попробуй, раз не веришь: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 15:16) [33]извини, чтото переклинило меня, блокирующий конечно
← →
Polevi © (2004-01-13 15:19) [34]Удалено модератором
Примечание: Сори, народ, это уже в чат... ;)
← →
Verg © (2004-01-13 15:26) [35]Удалено модератором
Примечание: Сори, народ, это уже в чат... ;)
← →
Verg © (2004-01-13 17:13) [36]Удалено модератором
Примечание: Не бойся, я с тобой... ;)
Страницы: 1 вся ветка
Форум: "Сети";
Текущий архив: 2004.03.28;
Скачать: [xml.tar.bz2];
Память: 0.58 MB
Время: 0.033 c