Вверх ↑
Ответов: 4658
Рейтинг: 760
#1: 2015-03-11 21:23:25 ЛС | профиль | цитата
Gunnman писал(а):
Откуда берется CurClientID как высчитывается?

Отсюда:


#pas
function TTCPServer._ExecuteAccept (T: TThread): Integer;
var
  Connection: TClientConnection;
  ClientSocket: TSocket;
  Addr: TSockAddr;
  AddrLen: Integer;
  FDRead: TSocketSet;
  TimeVal: TTimeVal;
begin

  TimeVal.tv_sec := 2; // Таймаут ожидания соединения - 2 сек
  TimeVal.tv_usec := 0;
  
  while (not T.Stopped) and (FSocket <> 0) do
  begin
    
    FDRead.Count := 1;
    FDRead.Socket := FSocket;
    
    // Ожидаем входящее подключение (поток приостанавливается на таймаут)

    case select(0, PFDSet(@FDRead), nil, nil, @TimeVal) of
      SOCKET_ERROR:
        begin
          if not T.Stopped then StopListen;
          Break;
        end;
      0: Continue; // Таймаут
    end;

    // Получено соединение - обрабатываем
    
    FillChar(Addr, SizeOf(TSockAddr), #0);
    AddrLen := SizeOf(TSockAddr);
    
    ClientSocket := accept(FSocket, @Addr, @AddrLen);

    if ClientSocket = INVALID_SOCKET then // Возникает в случае сбоя сети или закрытого FSocket
    begin
      if not T.Stopped then StopListen;
      Break;
    end;
    
    // Если за время таймаута было получено подключение, а сервер остановлен -
    // закрываем подключение (оно автора программы, вероятно, уже не интересует)
    if T.Stopped then
    begin
      shutdown(ClientSocket, SD_BOTH);
      closesocket(ClientSocket);
      Break;
    end;
    
    
    Connection := TClientConnection.Create;
    ConnectionAdd(Connection);
    with Connection do
    begin
      OnDisconnect := _OnDisconnect;
      if Assigned(Self.OnErrorSend) then OnErrorSend := _OnErrorSend;
      if Assigned(Self.OnProgress) then OnProgress := _OnProgress;
      if Assigned(Self.OnReceive) then OnReceive := _OnReceive;
      if Assigned(Self.OnSend) then OnSend := _OnSend;

      ReceiveDelay := FRecvDelay;
      RecvDelaySize := FRecvDelaySz;
      AsyncEvents := Self.AsyncEvents;
      SetSocket(ClientSocket, Integer(Addr.sin_addr), ntohs(Addr.sin_port));
      SendTimeout := Self.SendTimeout;
    end;

    if not T.Stopped then
    begin
      if Assigned(OnClientConnect) then
      begin
        if AsyncEvents <> ASYNC_EVENTS_ALL then
          T.Synchronize(_SyncClientConnect, Connection)
        else
          _SyncClientConnect(nil, Connection);
      end;
        
      //В OnClientConnect соединение может быть закрыто, поэтому проверяем на существование
      if ConnectionExists(Connection) then Connection.StartReceiving;
    end;    
  end;
end;
А именно, ID есть указатель на созданный здесь объект:
Connection := TClientConnection.Create;

Выходит, что в Delphi если создать некий объект, затем уничтожить его, а потом опять создать такой же, он вполне может получить адрес предыдущего. Избежать этого никак нельзя, да и не требуется. Важно то, что в любой момент времени в списке коннектов сервера всегда будут уникальные ID. Просто нужно помнить такую особенность. В схеме все равно нужно выполнять обработку onConnect/onDisconnect. Не могу представить ситуации, где важно, чтобы ID были уникальные. Они предназначены только для сопоставления событий/методов с указанным соединением. Нет соединения, нет с чем и сопоставлять.

А вот возможная ситуация, когда событие приходит из соединения 123, и пока обрабатывается, соединение закрывается и приходит новое соединение с тем же номером 123 и уже ему направляется ответ - это некорректная работа схемы: по отключению первого соединения 123, любая, предназначенная ему работа должна быть отменена. И для следующего 123 начата заново.
карма: 26

0
файлы: 1hjghjs.jpg [32.3KB] [615]