Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > Delphi программирование > Работа с сетью в Delphi
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 11.04.2018, 12:21   #1
vova65
Пользователь
 
Регистрация: 05.06.2011
Сообщений: 48
По умолчанию Асинхронный TCP

Здравствуйте камрады.
Помогите пожалуйста "умнику"

Есть класс-поток обработки сети
Код:
 //Поток обработки подключений, отключений, прием
 TNetworkThread = class(TThread)
 private
  //Состояние потока (поток запущен|ошибка запуска/поток остановлен)
  FWork:Boolean;
  //Пауза потока
  FPaused:Boolean;
 public
  WinSocket:TSocket;
  WinSocketAddr:sockaddr_in;
  procedure Paused(State:Boolean);
  procedure Execute(); Override;
  //
  constructor Create(CreateSuspended: Boolean);
 end;
vova65 вне форума Ответить с цитированием
Старый 11.04.2018, 12:28   #2
vova65
Пользователь
 
Регистрация: 05.06.2011
Сообщений: 48
По умолчанию

Выделение и освобождение структур клиентов
Код:
//Добавление нового клиента
function TNetwork.AddClient():TClientNetworkIndex1;
var Index:TClientNetworkIndex;
begin
 DebugTrace('- TNetworkClient.AddClient -');
 //
 Result := 0;
 //Проверяем есть ли свободный описатель
 if(ClientsCount < ClientsLength)then
 begin
  Index := ClientsFree[ClientsCount];
  //
  Clients[Index].State := cnsFree;
  Clients[Index].Index1Free := IndexToIndex1(ClientsCount);
  Clients[Index].BuffDataBase:=0;
  Clients[Index].BuffDataLength:=0;
  //
  ClientsCount:=ClientsCount+1;
  //
  Result:=IndexToIndex1(Index);
  //
  //
 end;
end;
//Удаление клиента
function TNetwork.DelClient(Index1Client:TClientNetworkIndex1):TClientNetworkIndex1;
var Index:TClientNetworkIndex;
    Index1Free:TClientNetworkIndex1;
    Temp:TClientNetworkIndex1;
begin
 Result := 0;
 //Проверяем границы
 if(Index1Client > 0) and (Index1Client <= ClientsLength)then
 begin
  Index := Index1ToIndex(Index1Client);
  //Проверяем занят ли удаляемый индекс состояний
  Index1Free := Clients[Index].Index1Free;
  
  if(Index1Free > 0) and (Index1Free <= ClientsCount)then
  begin
   //
   if(Index1Free < ClientsCount)then
   begin
    Temp := ClientsFree[Index1ToIndex(Index1Free)];
    ClientsFree[Index1ToIndex(Index1Free)] := ClientsFree[Index1ToIndex(ClientsCount)];
    ClientsFree[Index1ToIndex(ClientsCount)] := Temp;
    //
    Clients[ClientsFree[Index1ToIndex(Index1Free)]].Index1Free := Index1Free;
    //DebugTrace('- TNetworkClient.DelClient -'+inttostr(Index1Free)+' - '+inttostr(ClientsFree[Index1ToIndex(Index1Free)])+' - '+inttostr(ClientsCount));
   end;

   Clients[Index].Index1Free := 0;
   Clients[Index].State := cnsFree;
   //
   ClientsCount := ClientsCount - 1;
   //
   Result := Index1Client;
  end;// else
  //DebugTrace('- ERROR 2 -');
 end;// else
  //DebugTrace('- ERROR 1 -');
  //
end;
vova65 вне форума Ответить с цитированием
Старый 11.04.2018, 12:29   #3
vova65
Пользователь
 
Регистрация: 05.06.2011
Сообщений: 48
По умолчанию

Процедура асинхронной обработки TCP.
Код:
//Обработчик потока
procedure TNetworkThread.Execute();
var clientSocket:TSocket;
    clientAddr:sockaddr_in;
    sizeAddr:integer;
    arg:Longint;
    //
    //ClientNetwork:RClientNetwork;
    ClientIndex:TClientNetworkIndex1;
    //
    int:Integer;
    //
    ClientIndex1:TClientNetworkIndex1;
    //
    ClientState:TClientNetworkState;
    //
    time:Int64;
label
    End_Proc, Work_While,
    No_NewConnect, Cont_Recv, No_RecvClient;
begin
 DebugTrace('- TNetworkThread.Execute -');
 //
 ClientIndex1 := 0;
 ClientIndex := 0;
 //
 //Созданее сокета сервера
 WinSocket := socket(AF_INET, SOCK_STREAM, 0);
 if (WinSocket = INVALID_SOCKET) then
 begin
  Log.AddLogLine(lfErrorLog,'Ошибка создания сокета!',ltrCriticalError);
  goto End_Proc;
 end;
 //
 //Перевод сокета в неблокирующий режим
 arg := 1;
 if(ioctlsocket(WinSocket, FIONBIO, arg) = SOCKET_ERROR) then
 begin
  Log.AddLogLine(lfErrorLog,'Ошибка перевода сокета в неблокирующий режим!',ltrCriticalError);
  goto End_Proc;
 end;
 //!!!
 //Заполнение структуры адресса и связывание с ней сокета
 WinSocketAddr.sin_family := AF_INET;
 WinSocketAddr.sin_port := htons(8081);
 WinSocketAddr.sin_addr.S_addr := htonl(INADDR_ANY);
 if (WinSock.Bind(WinSocket, WinSocketAddr, sizeof(WinSocketAddr)))=SOCKET_ERROR then
 begin
  Log.AddLogLine(lfErrorLog,'Ошибка связывания сокета с адресом!',ltrCriticalError);
  goto End_Proc;
 end;
 //
 //Запуск прослушивания
 if (Listen(WinSocket, 10)) = SOCKET_ERROR then
 begin
  Log.AddLogLine(lfErrorLog,'Не могу начать прослушивание!',ltrCriticalError);
  goto End_Proc;
 end;
 //
 sizeAddr := sizeof(clientAddr);
 FWork := true;
vova65 вне форума Ответить с цитированием
Старый 11.04.2018, 12:30   #4
vova65
Пользователь
 
Регистрация: 05.06.2011
Сообщений: 48
По умолчанию

Код:
 //Цыкл прослушивания новых пакетов
 //##############################################################################
Work_While:
 if(not Terminated)then
 begin
  //Проверка паузы
  if(FPaused)then begin
   sleep(1000);
   goto No_NewConnect;
  end;
  //
  //
  //Если клиентов больше нуля
  if(Network.ClientsCount>0)then
  begin
   //DebugTrace('- Recv='+inttostr(Network.ClientsCount)+' = '+inttostr(Network.ClientsFree[ClientIndex]));
   //!!!!!!!!!!!!!!!!!!!!!!!!!
   ClientIndex := ClientIndex+1;
   if(ClientIndex >= Network.ClientsCount)then
    ClientIndex := 0;
   //
   ClientIndex1 := Network.ClientsFree[ClientIndex];
   //
   time:=RDTSC();
   //Log.AddLogLine(lfErrorLog,'КН - '+inttostr(ClientIndex1+1),ltrCriticalError);
   //
   ClientState := Network.Clients[ClientIndex1].State;
   //
   //
   if(ClientState = cnsWite)then
   begin
    //Проверка доступности данных клиента
    //int := Recv(Network.Clients[Index1ToIndex(ClientIndex)].ClientSocket, Network.Clients[Index1ToIndex(ClientIndex)].BuffData[0] , TClientsBuffSize, 0);
    int := Recv(Network.Clients[ClientIndex1].ClientSocket, Network.Clients[ClientIndex1].BuffData[Network.Clients[ClientIndex1].BuffDataBase] , TClientsBuffSize-Network.Clients[ClientIndex1].BuffDataBase, 0);
    if (int = INVALID_SOCKET) then begin
     if(WSAGetLastError = WSAEWOULDBLOCK)then
      goto Cont_Recv;
     //!!10054 - потеря связи с клиентом
     //
     if(WSAGetLastError = 10054) or (WSAGetLastError = 10053)then begin
      //Очистка структур клиентов
      Network.DisconnectClient(ClientIndex1+1);
      goto Cont_Recv;
     end;
     //
     Log.AddLogLine(lfErrorLog,'(Recv) ERROR CODE: '+inttostr(WSAGetLastError)+'',ltrFullError);
     //
     Network.DisconnectClient(ClientIndex1+1);
     goto Cont_Recv;
    end else begin
     Network.Clients[ClientIndex1].BuffDataBase := 0;
    end;
    //
    //Получение данных от клиента
    if(int = 0)then
    begin
     //Disconnect клиент отключился
     Network.SetState(ClientIndex1+1,cnsDisconectClient);
     //Вызов обработчика отключения клиента
     if Assigned(Network.FOnDisconnectClient)then
      Network.FOnDisconnectClient(ClientIndex1+1);
     //
     //Уничтожение(отключение) windows сокета
     CloseSocket(Network.Clients[ClientIndex1].ClientSocket);
     //
     if(ClientState <> cnsWork)then
     begin
      Network.DOnFreeClient(ClientIndex1+1);
     end;
     //
     Log.AddLogLine(lfErrorLog,'Отключение - '+inttostr(ClientIndex1+1),ltrCriticalError);
     //
    end else
    begin
     if(ClientState = cnsWite)then
     begin
      //Resive даные полученны и скопированны в буфер
      //DebugTrace('- Recv=='+inttostr(int));
      //
      Network.Clients[ClientIndex1].BuffDataLength := int;
      //Переводим клиента в режим обработки
      //Network.SetState(Network.ClientsFree[ClientIndex]+1,cnsWork);
      //
      if Assigned(Network.FOnReciveClient)then
       Network.FOnReciveClient(ClientIndex1+1);
      //Переводим клиента в режим ожидания
      if(Network.Clients[ClientIndex1].State = cnsWork)then
       Network.SetState(ClientIndex1+1,cnsWite);
      //
      Log.AddLogLine(lfErrorLog,'Прием - '+inttostr(ClientIndex1+1),ltrCriticalError);
      //
     end;
    end;
   end;
Cont_Recv:

   ClientState := Network.Clients[ClientIndex1].State;
   //Серверное отключение клиента
   if(ClientState >= cnsDisconectServer)then begin
    //showmessage('-'+inttostr(integer(ClientState)));
    if(ClientState = cnsDisconectServerSend)then begin
     Network.TransmitClientData(ClientIndex1+1,Network.Clients[ClientIndex1].BuffData,Network.Clients[ClientIndex1].BuffDataLength);
    end;
    //Вызов обработчика отключения клиента
    if Assigned(Network.FOnDisconnectClient)then
     Network.FOnDisconnectClient(ClientIndex1+1);
    //
    //Уничтожение(отключение) windows сокета
    if(ClientState = cnsDisconectServer)then
     CloseSocket(Network.Clients[ClientIndex1].ClientSocket);
    //
    Log.AddLogLine(lfErrorLog,'ОтключениеС - '+inttostr(ClientIndex1+1),ltrCriticalError);
    //
    Network.DOnFreeClient(ClientIndex1+1);
    goto No_RecvClient;
   end;
   //
   time:=RDTSC()-time;
   //Log.AddLogLine(lfErrorLog,'КК - '+inttostr(ClientIndex1+1)+'='+inttostr(time),ltrCriticalError);
  end;
  //
No_RecvClient:
  //
  time:=RDTSC();
  //Log.AddLogLine(lfErrorLog,'КПод - '+inttostr(0),ltrCriticalError);
  //Принимаем новое подключение
  //Network.Clients[ClientIndex1-1].ClientSocket := accept(WinSocket, @Network.Clients[ClientIndex1-1].ClientAddr, @sizeAddr);
  clientSocket := accept(WinSocket, @clientAddr, @sizeAddr);
  if (clientSocket = INVALID_SOCKET) then
  begin
   if(WSAGetLastError = WSAEWOULDBLOCK)then
    goto No_NewConnect;
   //
   Log.AddLogLine(lfErrorLog,'(Accept) ERROR CODE: '+inttostr(WSAGetLastError)+'',ltrWarningError);
   goto No_NewConnect;
   //
  end;
  //
  //Выделение структур под клиента
  ClientIndex1 := Network.AddClient();
  if(ClientIndex1 = 0)then
  begin
   //Буфер под клиента не выделен
   if(Network.ClientsCount >= TMaxClients)then begin
    Log.AddLogLine(lfErrorLog,'Превышено максимальное количество клиентов сервера',ltrFullError);
   end else begin
    Log.AddLogLine(lfErrorLog,'Структуры под нового клиента не выделенны',ltrFullError);
   end;
   //Сброс подключения
   CloseSocket(clientSocket);
   goto No_NewConnect;
  end;
  //
  //AddLogNetDump(lfNetDump, nil, 0);


  Network.Clients[ClientIndex1-1].ClientSocket := clientSocket;
  Network.Clients[ClientIndex1-1].ClientAddr := clientAddr;
  //Заполнение структуры клиента
  //ClientNetwork.Port := clientAddr.sin_port;
  //ClientNetwork.IP := inet_ntoa(clientAddr.sin_addr);
  Network.SetState(ClientIndex1,cnsWite);
  //Вызов события создания клиента
  if Assigned(Network.FOnCreateClient)then
      Network.FOnCreateClient(ClientIndex1);
  //Вызов события подключения клиента
  if Assigned(Network.FOnConnectClient)then
      Network.FOnConnectClient(ClientIndex1);
  //
  time:=RDTSC()-time;
  //Log.AddLogLine(lfErrorLog,'КПодК - '+inttostr(ClientIndex1)+'='+inttostr(time),ltrCriticalError);

  if(ClientIndex1 = 4)then
  begin
  //ClientIndex1 := Network.ClientsFree[ClientIndex];
   //showmessage('Error' +inttostr(Integer(Network.Clients[Network.ClientsFree[0]].State)) +'='+inttostr(Network.ClientsFree[0])+' - '+inttostr(Integer(Network.Clients[Network.ClientsFree[1]].State))+'='+inttostr(Network.ClientsFree[1])+' - '+inttostr(Integer(Network.Clients[Network.ClientsFree[2]].State))+'='+inttostr(Network.ClientsFree[2])+' - '+inttostr(Integer(Network.Clients[Network.ClientsFree[3]].State))+'='+inttostr(Network.ClientsFree[3])+' - '+inttostr(Integer(Network.Clients[Network.ClientsFree[4]].State))+'='+inttostr(Network.ClientsFree[4])+'');
  end;
  //
No_NewConnect:
  //
  sleep(10);
  goto Work_While;
 end;
 //
End_Proc:
 FWork := false;
end;




Извините за отладочный мусор в коде.
Код (если запускать отдельно от среды) вроде рабочий. Но со стабильностью я не уверен.

Подскажите насколько адекватна схема переиспользования памяти(структур) клиентов?

И как еще можно дописать код в procedure TNetworkThread.Execute(); чтоб он работал стабильно, и не упал от ошибок памяти или еще чего-то?
Буду благодарен за любые хорошие советы по доработке кода, особенно в ключе обработки ошибок.
vova65 вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Асинхронный пинг Sabre Win Api 5 30.01.2017 16:17
Асинхронный вызов в C# q_proger C# (си шарп) 7 16.12.2010 23:27
как создать TCP клиент, TCP сервер ? DreamMaster911 C/C++ Сетевое программирование 1 26.10.2010 15:05
Асинхронный просмотр Claster Помощь студентам 6 11.02.2010 15:38
Асинхронный сокет raspberry C/C++ Сетевое программирование 8 07.07.2009 16:51