Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 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_ACCEPT acSocket := accept(...)
так вот, участвуют только сокеты из второго пункта (у всех у них было FD_WRITE)

именно это я и имел ввиду


 
AlexAn ©   (2002-08-28 09:46) [14]

а насчет "работает .. сокет" - я имел ввиду, что мы (на FD_ACCEPT) имеем:
- серверный-ждущий сокет
- серверный-клиентский сокет, полученный ранее (или несколько)
- серверный-клиентский сокет, полученный по событию FD_ACCEPT acSocket := 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
1-101259
Inan61
2002-10-18 22:20
2002.10.31
Random Как сделать?


1-101234
lipskiy
2002-10-20 23:17
2002.10.31
Неявное описание типа данных? (Структура для настроек программы)


14-101440
MVova
2002-10-10 11:36
2002.10.31
Почему ICQ а не MSN


14-101486
VictorT
2002-10-11 17:41
2002.10.31
Как из аськи перенести контакт-лист и историю на другую машину?


1-101206
brestmarket
2002-10-21 11:38
2002.10.31
Почему может не работать этот код на некоторых PC: Windows или IE