powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Delphi [игнор отключен] [закрыт для гостей] / TCP-сокеты. Покритикуйте пожалуйста код
24 сообщений из 24, страница 1 из 1
TCP-сокеты. Покритикуйте пожалуйста код
    #39495723
A-MaR
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Имеются 2 приложения-службы, работающие по TCP-портам 49001 и 49002 (порты настраиваются). Используется TTCPBlockSocket из пакета Synapse.
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
150.
151.
152.
153.
154.
155.
156.
157.
158.
159.
160.
161.
162.
163.
164.
165.
166.
167.
168.
169.
170.
171.
172.
173.
174.
175.
176.
177.
178.
unit uEchoSrv;

interface  

uses
  Windows, Messages, SysUtils, StrUtils, Variants,Classes,
  StdCtrls, blcksock, uLogging, uLoggingThread;

type
  TProcessingData = function(const AData: string): string of object;

  TListenerThread = class(TLoggingThread)
     constructor Create(ASuspended: boolean; AIP: string; APort: Integer);
     destructor Destroy;override;
  private
     FSocket: TTCPBlockSocket;//объект сокета
     FThreadList: TList; //список дескрипторов потоков для работы с клиентами
     FProcessingData: TProcessingData;
     FHost: string;
     FPort: Integer;
     function GetIsTerminated: boolean;
  protected
     procedure Execute;override;
     procedure ServerStatus(Sender: TObject; Reason: THookSocketReason;
  const Value: String);
  public
     property Socket: TTCPBlockSocket read FSocket;
     property Host: string read FHost write FHost;
     property Port: Integer read FPort write FPort;
     property IsTerminated: boolean read GetIsTerminated;
     property ProcessingData: TProcessingData read FProcessingData write FProcessingData;
  end;

  TTCPThread = class(TLoggingThread)
  private
    FSocket: TTCPBlockSocket;
  protected
    var
      FProcessingData: TProcessingData;
    procedure Execute;override;
  public
    //ASocket - дескриптор сокета из очереди подключений.
    constructor Create(ASuspended: boolean; ASocket: integer);
    destructor Destroy; override;
    property Socket:TTCPBlockSocket read FSocket;
  end;

implementation    
{ TListenerThread }
 
constructor TListenerThread.Create(ASuspended: boolean; AIP: string; APort: Integer);
begin
  FSocket:=TTCPBlockSocket.Create;
  FThreadList:=TList.Create;
  FHost := AIP;
  FPort := APort;
  FSocket.OnStatus := ServerStatus;
  inherited Create(ASuspended);
  LogWriter.Suffix := '_EchoServer';
end;
 
destructor TListenerThread.Destroy;
var T:TTCPThread;
begin
  //завершаем все работающие нити
  while FThreadList.Count <> 0 do
    begin
      T:=TTCPThread(FThreadList.Extract(FThreadList.Last));
      T.Terminate;
      T.WaitFor;
      T.Free;
    end;
  //освобождаем память
  FThreadList.Free;
  FSocket.Free;
  inherited;
end;

function TListenerThread.GetIsTerminated: boolean;
begin
  Result := Terminated;
end;
 
procedure TListenerThread.Execute;
var T:TTCPThread;
begin
  FSocket.CreateSocket;//создаем новый сокет
  //связываем сокет с локальным адресом
  //выбор номера порта оставляем на усмотрение Synapse
  //FSocket.Bind(FSocket.LocalName,'0');
  FSocket.Bind(FHost,IntToStr(FPort));
  if FSocket.LastError=0 then begin //связываение с локальным адресом прошло успешно
     FSocket.Listen; //переходим в режим ожидания
    repeat
      if FSocket.CanRead(100) then begin//можем произвести чтение
       
        //получаем дескриптор сокета и создаем новую нить для клиента
        T:=TTCPThread.Create(false,FSocket.Accept);
        //определяем обработчик события ONStatus для новой нити
        T.Socket.OnStatus:=FSocket.OnStatus;
        T.FProcessingData := FProcessingData;
        //добавляем указатель на нить в список
        FThreadList.Add(pointer(T));
      end;
    until Terminated;//"гуляем" по циклу до тех пор, пока пользователь не остановит
  end
  else
    Self.LogWriter.Write('Ошибка при подключении ' + FSocket.LastErrorDesc, leError);//ошибка связывания - показываем её пользователю
end;

procedure TListenerThread.ServerStatus(Sender: TObject; Reason: THookSocketReason;
  const Value: String);
begin
  case Reason of
    HR_Bind: begin
               Self.LogWriter.Write ('Bind: '+Value);
               {lblAddress.Caption:=Server.Socket.GetLocalSinIP+':'+
                   IntToStr(Server.Socket.GetLocalSinPort) }
             end;
    HR_CanRead: Self.LogWriter.Write('Готов к чтению');
    HR_CanWrite: Self.LogWriter.Write('Готов к записи');
    HR_Listen: Self.LogWriter.Write('Прослушивание');
    HR_Accept: Self.LogWriter.Write('Подключение с адреса '+ Socket.GetRemoteSinIP);
    HR_ReadCount: Self.LogWriter.Write('Прочитано символов '+Value);
    HR_WriteCount: Self.LogWriter.Write('Записано символов '+Value);
    HR_Wait: Self.LogWriter.Write('Ожидание');
    HR_Error: Self.LogWriter.Write('Ошибка '+ Socket.LastErrorDesc, leError);
  end;
end;  

constructor TTCPThread.Create(ASuspended: boolean; ASocket: integer);
begin
  FSocket:=TTCPBlockSocket.Create;
  FSocket.Socket:=ASocket;
  FSocket.GetSins;
  inherited Create(ASuspended);
  LogWriter.Suffix := '_EchoServer';
end;
 
destructor TTCPThread.Destroy;
begin
  FSocket.Free;
  inherited;
end;
 
procedure TTCPThread.Execute;
var S, S_Out:string;
begin
 //работаем пока не поступит сигнал на остановку
  while not Terminated do begin
    try
      //есть данные ожидающие чтения
      if FSocket.WaitingData <> 0 then begin
        S_Out := '';
        //получаем данные
        s:=FSocket.RecvPacket(2000);
        Self.LogWriter.SuspendedWrite('Получена строка ' + s);
        //ошибок при получении данных не было
        if FSocket.LastError = 0 then begin
          if Assigned(FProcessingData) then begin
            S_Out := FProcessingData(S);
            Self.LogWriter.SuspendedWrite('Ответ сервера ' + S_Out);
            FSocket.SendString(S_Out);
          end;
        end
        else
          Self.LogWriter.Write('Ошибка при получении данных ' + FSocket.LastErrorDesc, leError);//ошибка связывания - показываем её пользователю
        Self.LogWriter.WriteList;
      end;
    except
      On E:Exception do
        Self.LogWriter.Write('TTCPThread.Execute ' + e.Message); 
    end;
    sleep(10);//"спим" 10 миллисекунд
  end;
end;

end.



и клиентское приложение, общающееся с этими службами через указанные порты, в том числе регистрация этих сервисов, запуск и остановка
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
unit uEchoClnt;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes,
  blcksock, StdCtrls, uLogging;

type
  TEchoClient = class (TLoger)   
 
  const
    cReadTimeout = 30000;
    constructor Create;
    destructor destroy; override;
  private
    FEnabled: boolean;
    FSocket: TTCPBlockSocket;
    FHost: string;
    FPort: Integer;
  public
    function Connect(AData: string = ''): string;
    procedure Disconnect;
    function SendString(AData: string; NeedConfirm: boolean = True; CustomTimeout: Integer = cReadTimeout): string;
    property Enabled_: boolean read FEnabled write FEnabled;
    property Host: string read FHost write FHost;
    property Port: Integer read FPort write FPort;
  end;

implementation
USES uCassTypes;

constructor TEchoClient.Create;
begin
  inherited;
  LogWriter.Suffix := '_EchoClient';
  FSocket := TTCPBlockSocket.Create;
  FSocket.RaiseExcept:=True;
  Host := 'localhost';
  Port := 49001;
end;

destructor TEchoClient.Destroy;
begin
  FreeAndNil(FSocket);
  inherited Destroy;
end;

function TEchoClient.Connect(AData: string = ''): string;
var SomeStr: string;
begin
  try  
    FSocket.Connect(FHost, IntToStr(FPort));  
    Self.LogWriter.SuspendedWrite(Format('Выполнено подключение к хосту %s на порт %d', [FHost, FPort]));
    if AData = '' then  
      Self.LogWriter.WriteList;  
    Result := '';
  except  
    on E:Exception do begin  
      if AData <> '' then  
        SomeStr := ' Строка ' + AData  
      else  
        SomeStr := '';  
      Self.LogWriter.Write(Format('Ошибка при подключении к порту %d (%s).%s',
        [FPort, E.Message, SomeStr]), leError);
      Enabled_ := false;  
      Result := E.Message;  
    end;  
  end;
end;

procedure TEchoClient.Disconnect;
begin
  Self.LogWriter.Write('Отключение от хоста');
  FSocket.CloseSocket;
end;

function TEchoClient.SendString(AData: string; NeedConfirm: boolean = True; CustomTimeout: Integer = cReadTimeout): string;
//NeedConfirm - если требуется ответ, например, запрос какого-либо параметра.
var Sending: boolean;
    i: integer;
begin
  Sending := false;
  i := 0;
  while (not Sending) and (i < 3) do begin
    try
      if NeedConfirm then begin
        Disconnect;
        Connect(AData);
      end;
      Self.LogWriter.SuspendedWrite('Передача строки ' + AData);
      FSocket.SendString(AData);
      if NeedConfirm then begin
        Result := FSocket.RecvPacket(CustomTimeout);
        Self.LogWriter.Write('Ответ сервера ' + Result);
      end
      else
        Self.LogWriter.Write('Ожидание ответа не предусмотрено');
      Sending := true;
    except
      ON e:Exception do begin
        Result := cSendError;
        Self.LogWriter.Write(Format('Ошибка при передаче %s, порт %d, строка %s', [e.Message, FPort, AData]), leError);
        sleep(100);
        i := i + 1;
      end;
    end;
  end;
  if not Sending then begin
    Disconnect;
    Connect;
  end;
end;

end.



Настройками предусмотрен также вариант работы без использования сокетов (по аналогии с командой sc), но в Windows10 для управления службами необходим запуск клиентской части от имени админа, что не устраивает безопасников.

В общем, все это вполне работает, но беда в том, что к рабочему месту подключен фискальник, приложение работает с ним через COM-порт, но TCP также задействуется для работы в качестве онлайн-кассы (порт 7778). И через несколько часов работы фискальник начинает с завидным постоянством выпадать в ошибку -1 (Нет связи) именно на тех точках, где взаимодействие со службами ведется посредством TCP. Там где без TCP - проблем нет, специально менял режимы работы на одних и тех же точках. Вывод - что-то не так в приведенном коде, но что именно?

(С сокетами работаю впервые, первоначальный код был заимствован из книги о Synapse Владислава Баженова, за что ему большое спасибо)
...
Рейтинг: 0 / 0
TCP-сокеты. Покритикуйте пожалуйста код
    #39495730
A-MaR
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
P.S. SendString из клиентской части выполняется примерно раз в минуту, изначально параметр NeedConfirm всегда был True, сейчас планирую от этого уйти, но на проблемных точках еще не тестировал.
...
Рейтинг: 0 / 0
TCP-сокеты. Покритикуйте пожалуйста код
    #39495731
Фотография wadman
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
A-MaR,

логирование же есть... Попробуй при ошибках дернуть GetLastError и WSAGetLastError.
...
Рейтинг: 0 / 0
TCP-сокеты. Покритикуйте пожалуйста код
    #39495752
A-MaR
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
wadman,

Так в самих сокетах ошибок нет - проблема в том, что они каким-то образом вышибают фискальник. А фискальник все что может сообщить - это ошибка -1 (Нет связи). Ну еще в его системном логе вот такие сообщения: TComPort ReadFile ERROR: 0x000003E3, Операция ввода/вывода была прервана из-за завершения потока команд или по запросу приложения.
Я ему напрямую точно никаких команд на прерывание не выдаю, следовательно гадят работающие сокеты.
...
Рейтинг: 0 / 0
TCP-сокеты. Покритикуйте пожалуйста код
    #39495756
asutp2
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
A-MaR,

утечки дескрипторов случайно нет?
...
Рейтинг: 0 / 0
TCP-сокеты. Покритикуйте пожалуйста код
    #39495794
Фотография wadman
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
A-MaR TComPort ReadFile ERROR: 0x000003E3, Операция ввода/вывода была прервана из-за завершения потока команд или по запросу приложения.
Это проблема потока, где-то ошибка в нем.
Оберни всё в try except и добавь логирование Exception.
...
Рейтинг: 0 / 0
TCP-сокеты. Покритикуйте пожалуйста код
    #39495828
fortress
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Если я правильно понял, то каждый раз при отправке строки (при NeedConfirm=True) будет заново устанавливаться соединение со службой. Если сокет уже подключен к серверу, зачем нужно его закрывать и подключаться снова?

По поводу ошибки фискальника. Может быть количество открытых соединений косвенно влияет на его работу? Например, как уже писали выше про утечку дескрипторов. Если попробовать во время проблем с фискальником проверить в системе количество открытых сетевых соединений?

Службам для обмена нужны именно сетевые сокеты TCP? Если они обе работают локально можно рассмотреть способ взаимодейcтвия через именованные каналы или разделяемую память (незнаю правда, как в этом случае обстоят дела с привелегиями).
...
Рейтинг: 0 / 0
TCP-сокеты. Покритикуйте пожалуйста код
    #39495831
asutp2
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
A-MaR,

в коде используется следующий участок:

Код: pascal
1.
2.
3.
4.
5.
      
      T:=TTCPThread(FThreadList.Extract(FThreadList.Last));
      T.Terminate;
      T.WaitFor;
      T.Free;



вопрос - у TTCPThread свойство FreeOnTerminate в какое значение установлено?
...
Рейтинг: 0 / 0
TCP-сокеты. Покритикуйте пожалуйста код
    #39495837
A-MaR
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
asutp2A-MaR,

утечки дескрипторов случайно нет?
По крайней мере в диспетчере задач дублирующих процессов нет, FASTMM4 не ругается (пробовал также запускать службы как обычное приложение).
...
Рейтинг: 0 / 0
TCP-сокеты. Покритикуйте пожалуйста код
    #39495840
A-MaR
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
wadmanA-MaR TComPort ReadFile ERROR: 0x000003E3, Операция ввода/вывода была прервана из-за завершения потока команд или по запросу приложения.
Это проблема потока, где-то ошибка в нем.
Оберни всё в try except и добавь логирование Exception.
Добавил по максимуму, на тестовом компе ошибок нет, но попробую завтра еще раз у клиента запустить.
...
Рейтинг: 0 / 0
TCP-сокеты. Покритикуйте пожалуйста код
    #39495850
A-MaR
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
fortressЕсли я правильно понял, то каждый раз при отправке строки (при NeedConfirm=True) будет заново устанавливаться соединение со службой. Если сокет уже подключен к серверу, зачем нужно его закрывать и подключаться снова?
Пробовал так. Если предыдущая отправка выполнялась с NeedConfirm=False, а текущая с True, то по непонятным причинам возвращается ответ предыдущей отправки. Как это лечить, пока не разобрался.

fortressЕсли попробовать во время проблем с фискальником проверить в системе количество открытых сетевых соединений?Спасибо, попробую.
...
Рейтинг: 0 / 0
TCP-сокеты. Покритикуйте пожалуйста код
    #39495876
asutp2
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
A-MaRasutp2A-MaR,

утечки дескрипторов случайно нет?
По крайней мере в диспетчере задач дублирующих процессов нет, FASTMM4 не ругается (пробовал также запускать службы как обычное приложение).
нет, речь не о процессах, а именно о дескрипторах
...
Рейтинг: 0 / 0
TCP-сокеты. Покритикуйте пожалуйста код
    #39496169
A-MaR
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
asutp2нет, речь не о процессах, а именно о дескрипторах
Понял, о чем речь. Блин, действительно в одной из служб все дескрипторы TTCPThread аккуратно прибивались при остановке службы, но в процессе работы копились и копились. Возможно в этом и причина.
...
Рейтинг: 0 / 0
TCP-сокеты. Покритикуйте пожалуйста код
    #39496394
A-MaR
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Странно: в типе THookSocketReason предусмотрен код HR_SocketClose с комментарием {:Socket closed by CloseSocket method.}, но даже если включить его в обработку статусов в TListenerThread.ServerStatus, сервер все равно не замечает, когда клиент выполняет у себя CloseSocket (возможно по этой причине автор и не включил его в первоначальный пример). Как в этом случае отлавливать отключение клиента, чтобы вовремя прибивать его дескриптор на сервере?
...
Рейтинг: 0 / 0
TCP-сокеты. Покритикуйте пожалуйста код
    #39496401
A-MaR
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
В общем, опытным путем выяснил, что этот статус HR_SocketClose срабатывает при закрытии потока на сервере, а не на клиенте. Так что видимо единственный выход - перед выполнением CloseSocket на клиенте отправлять серверу специальную команду без запроса подтверждения, и уже по этой команде сервер будет прибивать поток. Как-то примерно так (может есть более оптимальное решение?):
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
procedure TTCPThread.Execute;
var S, S_Out:string;
begin
 //работаем пока не поступит сигнал на остановку
  while not Terminated do begin
    try
      //есть данные ожидающие чтения
      if FSocket.WaitingData <> 0 then begin
        S_Out := '';
        //получаем данные
        s:=FSocket.RecvPacket(2000);
        Self.LogWriter.SuspendedWrite('Получена строка ' + s);
        //ошибок при получении данных не было
        if FSocket.LastError = 0 then begin
          if Assigned(FProcessingData) then begin
            S_Out := FProcessingData(S);
            Self.LogWriter.SuspendedWrite('Ответ сервера ' + S_Out);
            FSocket.SendString(S_Out);
          end;
        end
        else
          Self.LogWriter.Write('Ошибка при получении данных ' + FSocket.LastErrorDesc, leError);//ошибка связывания - показываем её пользователю
        //Если команда на завершение - сбрасываем флаг активности
        if UpperCase(s) = 'BYE' then
          IsActive := False;
        Self.LogWriter.WriteList;
      end;
    except
      On E:Exception do
        Self.LogWriter.Write('TTCPThread.Execute: ' + e.Message, leError);
    end;
    sleep(10);//"спим" 10 миллисекунд
  end;
end;

procedure TListenerThread.Execute;
var T:TTCPThread;

  procedure KillInactive;
  var i: integer;
      CurrentThread: TTCPThread;
  begin
    for i := FThreadList.Count-1 downto 0 do begin
      CurrentThread := TTCPThread(FThreadList[i]);
      if CurrentThread <> nil then begin
        if not CurrentThread.IsActive then begin
          FThreadList.Delete(i);
          CurrentThread.Terminate;
          CurrentThread.WaitFor;
          CurrentThread.Free;
          Self.LogWriter.Write(Format('Поток %d завершил работу и будет удален. Оставшееся количество потоков %d', [i, FThreadList.Count]));
        end;
      end;
    end;
  end;


begin
  try
    FSocket.CreateSocket;//создаем новый сокет
    //связываем сокет с локальным адресом
    //выбор номера порта оставляем на усмотрение Synapse
    //FSocket.Bind(FSocket.LocalName,'0');
    FSocket.Bind(FHost,IntToStr(FPort));
    if FSocket.LastError=0 then begin //связываение с локальным адресом прошло успешно
       FSocket.Listen; //переходим в режим ожидания
      repeat
        try
          if FSocket.CanRead(100) then begin//можем произвести чтение

            //получаем дескриптор сокета и создаем новую нить для клиента
            T:=TTCPThread.Create(false,FSocket.Accept);
            //Устанавливаем флаг активности
            T.IsActive := True;
            T.FreeOnTerminate := False;
            //определяем обработчик события ONStatus для новой нити
            T.Socket.OnStatus:=FSocket.OnStatus;
            T.FProcessingData := FProcessingData;
            //добавляем указатель на нить в список
            FThreadList.Add(pointer(T));
            Self.LogWriter.SuspendedWrite(Format('Количество TCP-потоков %d', [FThreadList.Count]));
          end;
          //Проверка на наличие неактивных потоков
          KillInactive;
        except
          on E:Exception do
            Self.LogWriter.Write('TListenerThread repeat: ' + e.Message, leError);
        end;
      until Terminated;//"гуляем" по циклу до тех пор, пока пользователь не остановит
    end
    else
      Self.LogWriter.Write('Ошибка при подключении ' + FSocket.LastErrorDesc, leError);//ошибка связывания - показываем её пользователю
    Self.LogWriter.WriteList;
  except
    on E:Exception do
      Self.LogWriter.Write('TListenerThread.Execute: ' + e.Message, leError);
  end;
end;

...
Рейтинг: 0 / 0
TCP-сокеты. Покритикуйте пожалуйста код
    #39496422
asutp2
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
A-MaR,

добавь поддержку таймаута при обмене с клиентами. Допустим не было за последние N секунд поступлений данных от клиента - тогда принудительно рвем с ним соединение
...
Рейтинг: 0 / 0
TCP-сокеты. Покритикуйте пожалуйста код
    #39496429
Фотография wadman
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
A-MaRи уже по этой команде сервер будет прибивать поток. Как-то примерно так (может есть более оптимальное решение?):
Это нормальное решение. Плюсом можно пинговать и если пинга не было 1-5 минут, то такое соединение считать мертвым.

П.С. Хотя, в ics закрытие соединения клиентом улавливается серверной стороной. Вот как они это делают? :-)
...
Рейтинг: 0 / 0
TCP-сокеты. Покритикуйте пожалуйста код
    #39496549
alekcvp
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
wadmanП.С. Хотя, в ics закрытие соединения клиентом улавливается серверной стороной. Вот как они это делают? :-)
Возможно так.

Но вообще, при попытке чтения из закрытого сокета должна возникать ошибка, возможно она и возникает, поэтому имеет смысл сделать что-то вроде:
автор
Код: pascal
1.
2.
3.
4.
5.
6.
7.
case FSocket.WaitingData of 
 -1: // WSAGetLastError и посмотреть что там находится.
  0: Sleep(10); // спим и продолжаем
else
  { Приём и обработка данных }
end;
{ тут Sleep() уже не нужен }    
...
Рейтинг: 0 / 0
TCP-сокеты. Покритикуйте пожалуйста код
    #39496551
alekcvp
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
alekcvp,
Причёт именно WSAGetLastError, потому что в Synapse в функции WaitingData почему-то не вызывается CheckError();
...
Рейтинг: 0 / 0
TCP-сокеты. Покритикуйте пожалуйста код
    #39496556
alekcvp
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Хотя нет, поторопился :(
Вот как WaitingData реализована в BlockSock.pas:
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
function TBlockSocket.WaitingData: Integer;
var
  x: Integer;
begin
  Result := 0;
  if synsock.IoctlSocket(FSocket, FIONREAD, x) = 0 then
    Result := x;
  if Result > c64k then
    Result := c64k;
end;



Если её выполнить на закрытом сокете, то, возможно, возникнет ошибка, но вы о ней не узнаете, т.к. функция тупо вернёт 0.
Поэтому, возможно, вместо неё стоит вызвать напрямую IoctlSocket(FSocket, FIONREAD, Value) и анализировать её код возврата и потом уже значение Value.
...
Рейтинг: 0 / 0
TCP-сокеты. Покритикуйте пожалуйста код
    #39496565
YuRock
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
wadmanП.С. Хотя, в ics закрытие соединения клиентом улавливается серверной стороной. Вот как они это делают? :-)Ну понятно, что (скорее всего) на сервере recv висит и ждет либо данных, либо SOCKET_ERROR. Я, во всяком случае, именно так и делаю обычно.
...
Рейтинг: 0 / 0
TCP-сокеты. Покритикуйте пожалуйста код
    #39496629
A-MaR
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Всем спасибо! В боевом режиме буду тестировать уже в понедельник;)
...
Рейтинг: 0 / 0
TCP-сокеты. Покритикуйте пожалуйста код
    #39496633
Фотография Квейд
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
asutp2A-MaR,

в коде используется следующий участок:

Код: pascal
1.
2.
3.
4.
5.
      
      T:=TTCPThread(FThreadList.Extract(FThreadList.Last));
      T.Terminate;
      T.WaitFor;
      T.Free;



Выделенное - лишнее, Terminate и WaitFor вызывает деструктор
...
Рейтинг: 0 / 0
TCP-сокеты. Покритикуйте пожалуйста код
    #39496642
YuRock
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Квейдasutp2A-MaR,

в коде используется следующий участок:

Код: pascal
1.
2.
3.
4.
5.
      
      T:=TTCPThread(FThreadList.Extract(FThreadList.Last));
      T.Terminate;
      T.WaitFor;
      T.Free;




Выделенное - лишнее, Terminate и WaitFor вызывает деструктор
Да, вообще можно
Код: pascal
1.
TTCPThread(FThreadList.Extract(FThreadList.Last)).Free


вместо этих 4-х строк и доп. переменной
...
Рейтинг: 0 / 0
24 сообщений из 24, страница 1 из 1
Форумы / Delphi [игнор отключен] [закрыт для гостей] / TCP-сокеты. Покритикуйте пожалуйста код
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]