Текущий архив: 2002.10.31;
Скачать: CL | DM;
Вниз
Проблема с использованием TServerSocket в ServiceApplication !!! Найти похожие ветки
← →
AlexAn © (2002-08-19 09:42) [0]Может кто-нибудь сталкивался с проблемой:
Серверный неблокирующий сокет работает в сервисе, при попытке клиента подключиться, соединение устанавливается от 10 до 20 сек., т.е. Accept срабатывет примерно после 15 сек. с момента вызова Connect у клиента. ?
Причем если весь этот алгоритм запихнуть не в TServiceApplication а в обычный TApplication, то проблем нет.
Еще есть один нюанс - с той же машины на которой стои сервис клиент соединяется моментально.
Если у кого есть какие-либо соображения по поводу, как решить эту проблему - мыльте плз.
← →
Digitman © (2002-08-19 11:54) [1]Что-то похожее на проблемы с DNS.
При работе TServerSocket в составе service application на другой машине ping по имени целевого хоста с клиентской машине какие временные результаты дает ?
← →
AlexAn © (2002-08-21 17:55) [2]это конечно могло бы быть похоже на DNS проблемы, только:
- почему они не возникают при 1-ом коннекте
- почему TIdServer нормально работает
- я не использую имя, а адресс !!!
проблема не в этом
← →
Digitman © (2002-08-21 18:03) [3]
> - почему они не возникают при 1-ом коннекте
Если TServerSocket работает в режиме stNonBlocking, это может быть вполне объяснимо тем, что при поступлении запроса на очередной коннект сервер занят обработкой прочих сообщений, и Accept() стоит в очереди.
> - почему TIdServer нормально работает
Не берусь утверждать (не рассматривал попросту TIdServer детально), но не исключено, что именно по вышеуказанной же причине : режим TIdServer по-умолчанию может быть и ThreadBlocking.
> я не использую имя, а адресс !!!
Тогда DNS вроде бы отпадает. Тем более - обрати серьезное внимание на режим работы серверного компонента
← →
AlexAn © (2002-08-26 13:03) [4]По поводу первого пункта у меня и есть несколько вопросов:
- во-первых, почему такая проблема возникает только в сервисе, обычное приложение работает нормально?
- почему все остальные Message-и проходят нормально, кроме FD_ACCEPT?
- TIdSever - блокирующий, а мне нужно именно без блокировки
я сейчас переаисываю все это на API, причем к каждому SOCKET вешаю свое окно со своим потоком, так чтобы они не пересекались. Посмотрим, что из этого получиться. Если не пойдет через оконную процедуру, думаю попробовать через SockEvent - тоже наверное вариант ;-)
!!! Но вообще-то обидно, потому-как в хелпе по дефам приведен пример для неблокирующего сока под сервис и есл его передрать один к одному, то такая ф-ня получается!!!
приходится тратить время на обдумывание
← →
Digitman © (2002-08-26 13:44) [5]
> думаю попробовать через SockEvent
Это - наилучший вариант для блокирующих гнезд в доп.потоках.
Посложнее, конечно, будет, но зато ты уже не зависишь никоим образом от очередей и диспетчеров оконных сообщений
← →
AlexAn © (2002-08-27 10:47) [6]короче, я нашел глюк
можно, конечно, меня за это и по рукам - но интересная ситуация:
проблема вся в send().
код вот такой:
procedure TsvcTcp.ServerSocketAccept(Sender: TObject;
Socket: TCustomWinSocket);
var
i: Integer;
r_str: PString;
begin
New(r_str);
Socket.Data := r_str;
for i := 0 to ServerSocket.Socket.ActiveConnections - 1 do
begin
if ServerSocket.Socket.Connections[i].Handle <> Socket.Handle then
begin
ServerSocket.Socket.Connections[i].SendText("addcli: " + Socket.RemoteHost + " " + Socket.RemoteAddress);
end;
end;
end;
если убрать
ServerSocket.Socket.Connections[i].SendText("addcli: " + Socket.RemoteHost + " " + Socket.RemoteAddress);
все работает
← →
AlexAn © (2002-08-27 10:51) [7]но это еще не все !!!
я перенес весь этот цикл в OnWrite и там он тоже тормозит, хотя во всех остальных случаях вроде все в порядке
буду разбираться !!!
← →
Digitman © (2002-08-27 10:54) [8]>AlexAn
Ну разумеется ! В Accept-обработчике такие вещи недопустимы !
Но почему это, по твоему мнению, "глюк" - вот это уже гораздо интереснее) ... Не "глюк" это вовсе, а нормальная логика работы send-методов
← →
AlexAn © (2002-08-27 11:34) [9]дело в том, что работает не сокет полученный по accept, а сокеты, которые уже соединены, я честно говоря не пойму, каким они тут боком ?
← →
Digitman © (2002-08-27 12:18) [10]что значит, по твоему , "работает ... сокет" ?
ты считаешь, что send-метод работает мгновенно ?
прокомментируй ход своих мыслей для строчки
ServerSocket.Socket.Connections[i].SendText(...);
Как она работает, по-твоему ? Что происходит при выполнении send-метода в том или ином режиме сервера ?
← →
AlexAn © (2002-08-28 09:38) [11]в блокирующем (через WSAAsyncSelect) режиме если данные не отосланы возвращается WSAEWOULDBLOCK, и данные отсылаются из буфера системы, после чего вызывается оконная процедура с FD_WRITE.
если данные отослались, то возвращается кол-во отсосланных байт, что у меня и происходит, т.к. сообщения маленькие.
но задержка send на 10 сек при посылке на 100Мбит (длинна ~20байт) - это КРУТО!!!
← →
AlexAn © (2002-08-28 09:39) [12]!!! я описался - в неблокирующем конечно !!!
← →
AlexAn © (2002-08-28 09:45) [13]а насчет "работает .. сокет" - я имел ввиду, что мы (на FD_ACCEPT) имеем:
- серверный-ждущий сокет
- серверный-клиентский сокет, полученный ранее (или несколько)
- серверный-клиентский сокет, полученный по событию FD_ACCEPTacSocket := accept(...)
так вот, участвуют только сокеты из второго пункта (у всех у них было FD_WRITE)
именно это я и имел ввиду
← →
AlexAn © (2002-08-28 09:46) [14]а насчет "работает .. сокет" - я имел ввиду, что мы (на FD_ACCEPT) имеем:
- серверный-ждущий сокет
- серверный-клиентский сокет, полученный ранее (или несколько)
- серверный-клиентский сокет, полученный по событию FD_ACCEPTacSocket := accept(...)
так вот, участвуют только сокетыиз второго пункта (у всех у них было FD_WRITE)
именно это я и имел ввиду
← →
Reindeer Moss Eater (2002-08-28 10:06) [15]А каков глубокий смысл неблокирующего сокета в сервисе???
← →
Digitman © (2002-08-28 10:18) [16]Так ты же не даешь приложению возможности обрабатывать потенциальные сообщения, могущие возникнуть в момент выполнения цикла с вызовом Send-метода !
Тогда уж вот так примерно делай :
i := 0;
with ServerSocket.Socket do
while i < ActiveConnections do
begin
if Connections[i].Handle <> Socket.Handle then
try
while Connections[i].SendText(..) <> 0 do
Application.ProcessMessages;
except
end;
Inc(i);
end;
Но только не в OnAccept ! Как минимум - в OnClientConnect
← →
AlexAn © (2002-08-28 10:21) [17]я об этом думал, только у меня сервисное приложение, с обычным никаких проблем
← →
AlexAn © (2002-08-28 10:27) [18]и еще вопрос: какие события возникают вместе с
send
?
← →
AlexAn © (2002-08-28 10:35) [19]Reindeer Moss Eater > какой вариант с блокирующим сокетом (в смысле реализации), если сервер должен рассылать события клиентам не по запросу, а в момент возникновения события на сервере (желательно в реальном времени)?
← →
Digitman © (2002-08-28 10:39) [20]В смысле - события TCustomWinSocket ?
Возможны OnWrite (факт доступности буфера передачи гнезда)
и OnError (отказ транспорта по многим причинам, например, разрыв соединения по инициативе партнера в момент передачи)
← →
AlexAn © (2002-08-28 10:57) [21]дело в том, что я вынес цикл отсылки в отдельную нить:
unit thrd_wr;
interface
uses
Classes, ScktComp, MessageFrm, SysUtils, WinSock;
type
PSDstr = ^TSDstr;
TSDstr = record
r_str,
UserName: string;
NeedSend: Boolean;
Data: Pointer;
end;
TWriteThread = class(TThread)
public
FServerSocket: TServerSocket;
FSocket: TCustomWinSocket;
constructor Create(ServerSocket: TServerSocket; Socket: TCustomWinSocket);
procedure Execute; override;
end;
TWriteStrThread = class(TThread)
public
FSocket: TCustomWinSocket;
FText: string;
constructor Create(AText: string; Socket: TCustomWinSocket);
procedure Execute; override;
end;
implementation
{ TWriteThread }
constructor TWriteThread.Create(ServerSocket: TServerSocket; Socket: TCustomWinSocket);
begin
inherited Create(false);
FServerSocket := ServerSocket;
FSocket := Socket;
FreeOnTerminate := true;
end;
procedure TWriteThread.Execute;
var
i: Integer;
begin
FSocket.SendText("write data");
for i := 0 to FServerSocket.Socket.ActiveConnections - 1 do
begin
if FServerSocket.Socket.Connections[i].Handle <> FSocket.Handle then
begin
TWriteStrThread.Create("addcli: " + PSDstr(FSocket.Data).UserName + " " + FSocket.RemoteHost + " " + FSocket.RemoteAddress, FServerSocket.Socket.Connections[i]);
end;
end;
end;
{ TWriteStrThread }
constructor TWriteStrThread.Create(AText: string;
Socket: TCustomWinSocket);
begin
inherited Create(false);
//Priority := tpLowest;
FSocket := Socket;
FText := AText;
end;
procedure TWriteStrThread.Execute;
begin
send(FSocket.SocketHandle, Pointer(FText)^, Length(FText), 0);
end;
end.
← →
Digitman © (2002-08-28 11:14) [22]а почему не воспользоваться штатным режимом TServerSocket.ServerType = stThreadBlocking ?
просто реализуй наследника TServerClientThread, тело ClientExecute которого будет полностью контролировать транспорт отдельного гнезда
кр.того, TServerWinSocket реализует кэширование транспотных кодовых потоков; твой же вариант совершенно не учитывает того факта, что всякий вызов CreateThread() имеет значительную время- и ресурсоемкость, и для системы это выглядит как старт некоего холодного двигателя в холодную же погоду - медленно и тяжело
см. события OnGetThread, OnGetSocket
← →
AlexAn © (2002-08-28 11:40) [23]хорошо, как отослать клиенту сообщение от сервера, когда сервер находится в состоянии recv если сокет блокирующий?
← →
Digitman © (2002-08-28 11:49) [24]а зачем ему постоянно находиться в состоянии recv ? да и зачем ему обязательно в блок.режиме работать ? после создания гнезда и соотв трансп.потока в теле ClientExecute переведи гнездо в асинхронный неблок.режим вызовом WSAEventSelect и лови гнездовые нотификации в цикле MsgWaitForMultipleObjects ! При этом тр.поток большинство времени находится в состоянии ожидания имеет возможность мгновенно реагироватьь как на осн.трансп.события (FD_READ, FR_WRITE, FD_CLOSE), так и на внешние сообщения. А внешним соообщением ты можешь передать тр.потоку инф-цию о необходимости выполнить send с такими-то параметрами
← →
AlexAn © (2002-08-29 09:12) [25]Ну я вобщем как раз над этим и работаю, просто я хотел обойтись средствами Delphi не залезая в API.
Страницы: 1 вся ветка
Текущий архив: 2002.10.31;
Скачать: CL | DM;
Память: 0.54 MB
Время: 0.015 c