Здравствуйте.
Вот мой код, который ПОЧТИ абсолютно нормально работает.
ПОЧТИ, потому, что при не нормальном разрыве сети (отключение питание на машине клиента, порыв сетевого кабеля, отказ хаба-роутера и т.д.) когда сервер НЕ получает события Disconnect от клиента и, соответственно считает клиента подключенным, после повторного подключения клиента к серверу в процедуре таймера опроса клиентов (TForm1.TimerClientTimer) на строке
Код:
// определяем адрес, кто на этом сокете...
Address := Server.Socket.Connections[i].RemoteAddress;
возникает критическая ошибка List index of bound.
Я понимаю, что при обрыве и повторном соединении клиента список соединений сервера содержит 2 "активных" коннекта.
Один "мертвый", т.е. не получивший события Disconnect и второй, который получился при соединении клиента после исправления ситуации с потерей связи и теперь он актуальный. Даже если я ставлю эту ситуацию в try-except(try-finally) "мертвый" коннект из списка ни куда не девается.
Вопрос:
КАК от этого "мертвяка" избавиться?
КАК его удалить из списка Server.Socket.ActiveConnections?
Сервер:
Код:
type
TPacket = record
Code : integer;
iValue : integer;
aValue : array[0..500] of char;
end;
.......
procedure TForm1.FormCreate(Sender: TObject);
begin
try
Server := TServerSocket.Create(self);
Server.OnClientConnect := Server_ClientConnect;
Server.OnClientDisconnect := Server_ClientDisConnect;
Server.OnClientRead := Server_ClientRead;
Server.OnClientError := Server_Error;
except
...
end;
end;
procedure TForm1.Server_Error(Sender: TObject; Socket: TCustomWinSocket;
ErrorEvent: TErrorEvent; var ErrorCode: Integer);
begin
Socket.Close;
ErrorCode:=0;
end;
procedure TForm1.Server_ClientConnect(Sender: TObject; Socket: TCustomWinSocket);
begin
// если таймер не запущен, запускаем...
if not self.TimerClient.Enabled then begin
self.TimerClient.Enabled := true;
end;
end;
procedure TForm1.Server_ClientDisConnect(Sender: TObject; Socket: TCustomWinSocket);
begin
// активных коннектов нет, таймер останавливаем...
if Server.Socket.ActiveConnections = 0 then
self.TimerClient.Enabled := false;
end;
procedure TForm1.Server_ClientRead(Sender: TObject; Socket: TCustomWinSocket);
var
Packet:TPacket;
begin
Socket.ReceiveBuf(Packet, SizeOf(Tpacket));
case Packet.Code of
.....
end;
end;
procedure TForm1.TimerClientTimer(Sender: TObject);
var
i : integer;
Address : string;
sSocket: TCustomWinSocket;
Packet:TPacket;
begin
self.TimerClient.Enabled := false;
// пройтись по всем активным соединениям...
y := Server.Socket.ActiveConnections;
for i:=0 to y-1 do begin
// определяем адрес, кто на этом сокете...
Address := Server.Socket.Connections[i].RemoteAddress;
// получаем сам сокет...
sSocket := Server.Socket.Connections[i];
if sSocket <> nil then begin
// формируем запрос к клиенту...
ZeroMemory(@Packet, Sizeof(TPacket));
...
// ... и посылаем его...
sSocket.SendBuf(Packet, Sizeof(TPacket));
end;
// теперь ожидаем ответ от клиента 50 милисекунд
end;
// запуск таймера
self.TimerClient.Enabled := true;
end;
Client:
Код:
procedure TForm1.FormCreate(Sender: TObject);
begin
self.qtty := 0;
Client := TClientSocket.Create(self);
Client.Port := 5555;
Client.Address := IP_Adress;
Client.OnError := Client_Error;
Client.OnConnect := Client_Connect;
Client.OnDisconnect := Client_Disconnect;
Client.OnRead := Client_Read;
end;
procedure TForm1.Client_Connect(Sender: TObject; Socket: TCustomWinSocket);
begin
InitConnect := false;
Timer1.Enabled:=false;
SendMessage(Socket, INIT, StrToInt(sLogin), Pchar(sPass));
end;
procedure TForm1.Client_Disconnect(Sender: TObject; Socket: TCustomWinSocket);
begin
end;
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
Client.Close;
end;
procedure TForm1.Client_Error(Sender: TObject; Socket: TCustomWinSocket;
ErrorEvent: TErrorEvent; var ErrorCode: Integer);
begin
ErrorCode:=0;
end;
procedure TForm1.SendMessage(Socket: TCustomWinSocket; Code, Value:integer; Other:string);
var
Packet:TPacket;
begin
ZeroMemory(@Packet, Sizeof(TPacket));
...
Socket.SendBuf(Packet, Sizeof(TPacket));
end;
procedure TForm1.Timer1Timer(Sender: TObject);
begin
self.Timer1.Enabled := false;
inc(self.qtty);
Client.Close;
sleep(1000);
Application.ProcessMessages;
Client.Open;
self.Timer1.Enabled := true;
end;