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

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

Проблема с использованием TServerSocket в ServiceApplication !!! [NT4, Win2k, WinXP]


Страницы:   1 2

AlexAn ©   (2002-08-19 09:42:00) 

Может кто-нибудь сталкивался с проблемой:
Серверный неблокирующий сокет работает в сервисе, при попытке клиента подключиться, соединение устанавливается от 10 до 20 сек., т.е. Accept срабатывет примерно после 15 сек. с момента вызова Connect у клиента. ?
Причем если весь этот алгоритм запихнуть не в TServiceApplication а в обычный TApplication, то проблем нет.
Еще есть один нюанс - с той же машины на которой стои сервис клиент соединяется моментально.
Если у кого есть какие-либо соображения по поводу, как решить эту проблему - мыльте плз.


AlexAn   (2002-08-29 09:12:00) [1]

Ну я вобщем как раз над этим и работаю, просто я хотел обойтись средствами Delphi не залезая в API.


Digitman   (2002-08-28 11:49:00) [2]

а зачем ему постоянно находиться в состоянии recv ? да и зачем ему обязательно в блок.режиме работать ? после создания гнезда и соотв трансп.потока в теле ClientExecute переведи гнездо в асинхронный неблок.режим вызовом WSAEventSelect и лови гнездовые нотификации в цикле MsgWaitForMultipleObjects ! При этом тр.поток большинство времени находится в состоянии ожидания имеет возможность мгновенно реагироватьь как на осн.трансп.события (FD_READ, FR_WRITE, FD_CLOSE), так и на внешние сообщения. А внешним соообщением ты можешь передать тр.потоку инф-цию о необходимости выполнить send с такими-то параметрами


AlexAn   (2002-08-28 11:40:00) [3]

хорошо, как отослать клиенту сообщение от сервера, когда сервер находится в состоянии recv если сокет блокирующий?


Digitman   (2002-08-28 11:14:00) [4]

а почему не воспользоваться штатным режимом TServerSocket.ServerType = stThreadBlocking ?

просто реализуй наследника TServerClientThread, тело ClientExecute которого будет полностью контролировать транспорт отдельного гнезда

кр.того, TServerWinSocket реализует кэширование транспотных кодовых потоков; твой же вариант совершенно не учитывает того факта, что всякий вызов CreateThread() имеет значительную время- и ресурсоемкость, и для системы это выглядит как старт некоего холодного двигателя в холодную же погоду - медленно и тяжело

см. события OnGetThread, OnGetSocket


AlexAn   (2002-08-28 10:57:00) [5]

дело в том, что я вынес цикл отсылки в отдельную нить:

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 10:39:00) [6]

В смысле - события TCustomWinSocket ?
Возможны OnWrite (факт доступности буфера передачи гнезда)
и OnError (отказ транспорта по многим причинам, например, разрыв соединения по инициативе партнера в момент передачи)


AlexAn   (2002-08-28 10:35:00) [7]

Reindeer Moss Eater > какой вариант с блокирующим сокетом (в смысле реализации), если сервер должен рассылать события клиентам не по запросу, а в момент возникновения события на сервере (желательно в реальном времени)?


AlexAn   (2002-08-28 10:27:00) [8]

и еще вопрос: какие события возникают вместе с send?


AlexAn   (2002-08-28 10:21:00) [9]

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


Digitman   (2002-08-28 10:18:00) [10]

Так ты же не даешь приложению возможности обрабатывать потенциальные сообщения, могущие возникнуть в момент выполнения цикла с вызовом 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


Reindeer Moss Eater   (2002-08-28 10:06:00) [11]

А каков глубокий смысл неблокирующего сокета в сервисе???


AlexAn   (2002-08-28 09:46:00) [12]

а насчет "работает .. сокет" - я имел ввиду, что мы (на FD_ACCEPT) имеем:
- серверный-ждущий сокет
- серверный-клиентский сокет, полученный ранее (или несколько)
- серверный-клиентский сокет, полученный по событию FD_ACCEPT acSocket := accept(...)
так вот, участвуют только сокетыиз второго пункта (у всех у них было FD_WRITE)

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


AlexAn   (2002-08-28 09:45:00) [13]

а насчет "работает .. сокет" - я имел ввиду, что мы (на FD_ACCEPT) имеем:
- серверный-ждущий сокет
- серверный-клиентский сокет, полученный ранее (или несколько)
- серверный-клиентский сокет, полученный по событию FD_ACCEPT acSocket := accept(...)
так вот, участвуют только сокеты из второго пункта (у всех у них было FD_WRITE)

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


AlexAn   (2002-08-28 09:39:00) [14]

!!! я описался - в неблокирующем конечно !!!


AlexAn   (2002-08-28 09:38:00) [15]

в блокирующем (через WSAAsyncSelect) режиме если данные не отосланы возвращается WSAEWOULDBLOCK, и данные отсылаются из буфера системы, после чего вызывается оконная процедура с FD_WRITE.
если данные отослались, то возвращается кол-во отсосланных байт, что у меня и происходит, т.к. сообщения маленькие.

но задержка send на 10 сек при посылке на 100Мбит (длинна ~20байт) - это КРУТО!!!


Digitman   (2002-08-27 12:18:00) [16]

что значит, по твоему , "работает ... сокет" ?
ты считаешь, что send-метод работает мгновенно ?
прокомментируй ход своих мыслей для строчки

ServerSocket.Socket.Connections[i].SendText(...);

Как она работает, по-твоему ? Что происходит при выполнении send-метода в том или ином режиме сервера ?


AlexAn   (2002-08-27 11:34:00) [17]

дело в том, что работает не сокет полученный по accept, а сокеты, которые уже соединены, я честно говоря не пойму, каким они тут боком ?


Digitman   (2002-08-27 10:54:00) [18]

>AlexAn

Ну разумеется ! В Accept-обработчике такие вещи недопустимы !
Но почему это, по твоему мнению, "глюк" - вот это уже гораздо интереснее) ... Не "глюк" это вовсе, а нормальная логика работы send-методов


AlexAn   (2002-08-27 10:51:00) [19]

но это еще не все !!!

я перенес весь этот цикл в OnWrite и там он тоже тормозит, хотя во всех остальных случаях вроде все в порядке

буду разбираться !!!


AlexAn   (2002-08-27 10:47:00) [20]

короче, я нашел глюк
можно, конечно, меня за это и по рукам - но интересная ситуация:
проблема вся в 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);

все работает


Страницы:   1 2

Наверх

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