Форум программистов
 
Контакты: о проблемах с регистрацией, почтой и по другим вопросам пишите сюда - alarforum@yandex.ru, проверяйте папку спам! Обязательно пройдите активизацию e-mail.
Внимание! Некоторое время письма не доходят до аккаунтов MAIL RU GROUP, не доходят на все почтовые ящики mail.ru, inbox.ru, bk.ru. Пишите им жалобы, чтобы быстрее восстановили получение писем, регистрируйтесь через яндекс почту и gmail, туда письма с активизацией доходят.

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

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

Ответ
 
Опции темы
Старый 11.04.2018, 13:21   #1
vova65
Пользователь
 
Регистрация: 05.06.2011
Сообщений: 48
Репутация: 10
По умолчанию Асинхронный 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, 13:28   #2
vova65
Пользователь
 
Регистрация: 05.06.2011
Сообщений: 48
Репутация: 10
По умолчанию

Выделение и освобождение структур клиентов
Код:

//Добавление нового клиента
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, 13:29   #3
vova65
Пользователь
 
Регистрация: 05.06.2011
Сообщений: 48
Репутация: 10
По умолчанию

Процедура асинхронной обработки 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, 13:30   #4
vova65
Пользователь
 
Регистрация: 05.06.2011
Сообщений: 48
Репутация: 10
По умолчанию

Код:

 //Цыкл прослушивания новых пакетов
 //##############################################################################
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 вне форума   Ответить с цитированием
Ответ

Опции темы

Ваши права в разделе
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.

Быстрый переход

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


20:45.


Powered by vBulletin® Version 3.8.8 Beta 2
Copyright ©2000 - 2018, Jelsoft Enterprises Ltd.

RusProfile.ru


Справочник российских юридических лиц и организаций.
Проекты отопления, пеллетные котлы, бойлеры, радиаторы
интернет магазин respective.ru