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

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

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

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

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

Ответ
 
Опции темы Поиск в этой теме
Старый 25.07.2010, 13:48   #1
3D Hunter
Сумрачная тень
Форумчанин
 
Аватар для 3D Hunter
 
Регистрация: 05.03.2009
Сообщений: 689
Вопрос TCPServer и TCPClient - как работать?

Здравствуйте, коллеги. Такой вопрос: как работать с этими компонентами в блокирующем многопоточном режиме? Инфы в инете перерыл море, кругом вода и полезного мизер.
Вот код, который я мучаю. Здесь есть клиент, отсылающий каждую секунду пакет данных. Если ответа от сервера не приходит, он пишет данные в черный ящик, и только когда пришел ответ от сервера о получении, то клиент сбрасывает все содержимое ящика.
http://3dh.nm.ru/0.rar

Люди, подскажите или киньте ссылки на их использование. Пожалуйста! Очень нужно!
"ковыряю изнутри" (с)
3D Hunter вне форума Ответить с цитированием
Старый 26.07.2010, 11:57   #2
3D Hunter
Сумрачная тень
Форумчанин
 
Аватар для 3D Hunter
 
Регистрация: 05.03.2009
Сообщений: 689
По умолчанию

Люди, ну если неохота код шарить, хоть линками ткните мне про эти компоненты или книги, где про них есть хоть что-нить. Хочу построить клиент-сервер именно на них, ибо знаю, что вещь мощная и можно с лихвой обойтись без винсока
"ковыряю изнутри" (с)
3D Hunter вне форума Ответить с цитированием
Старый 27.07.2010, 09:58   #3
3D Hunter
Сумрачная тень
Форумчанин
 
Аватар для 3D Hunter
 
Регистрация: 05.03.2009
Сообщений: 689
По умолчанию

ладно, тогда конкретные вопросы. Говорю сразу: TCPClient в режиме bmBlocking, TCPServer - bmBlockThreading.
1) как корректно завершить сервер, разорвав все потоки соединения? Просто TCPServer.Close в событии вормы onDestroy?
2) у клиента в тайсере идет передача и прием данных. Сначала клиент получает данные от сервера. И если получена строка-сигнал, то клиент отправляет дальше в этом же таймере, т.е. здесь вызовы ReciveLn и SendLn
код:
Код:
procedure TFAGEmul.timer_sendTimer(Sender: TObject);
begin
  timer_send.Enabled:=False;
  BBPacket:=tcp_Autograph.Receiveln;
  Application.ProcessMessages;
  if BBPacket='d' then
  begin
    tcp_AutographDisconnect(Application);
    Application.ProcessMessages;
    Exit;
  end;
  AllowSend:=BBPacket=AuReceive;}
  if BlackBox=#0 then BlackBox:=AuFullPacket
  else BlackBox:=BlackBox+AuPartPacket;
  if AllowSend then
  begin
    AllowSend:=False;
    tcp_Autograph.Sendln(BlackBox);
    Application.ProcessMessages;
    BlackBox:=#0;
  end;
  mm_box.Text:=BlackBox;
  timer_send.Enabled:=True;
end;
"ковыряю изнутри" (с)
3D Hunter вне форума Ответить с цитированием
Старый 27.07.2010, 10:09   #4
mss
Заблокирован
 
Регистрация: 27.05.2010
Сообщений: 1,099
По умолчанию

> Просто TCPServer.Close в событии вормы onDestroy?

TCPServer.Free;

Но следует принять алгоритмические меры к тому чтобы треды клиентских соединений максимально оперативно реагировали на флаг Terminated.
mss вне форума Ответить с цитированием
Старый 27.07.2010, 10:39   #5
3D Hunter
Сумрачная тень
Форумчанин
 
Аватар для 3D Hunter
 
Регистрация: 05.03.2009
Сообщений: 689
По умолчанию

хорошо, более подробно.
Такой код будет корректен?
Код:
procedure TFParser.FormCreate(Sender: TObject);
begin
  MaxDev:=1;
  DevCount:=0;
  tcp_parser.Open;
end;
procedure TFParser.FormDestroy(Sender: TObject);
var i:Integer;
begin
  for i:=0 to tcp_parser.ServerSocketThread.ThreadPool.Count-1 do
  TAuThread(tcp_parser.ServerSocketThread.ThreadPool[i]^).Terminate;
  while tcp_parser.ServerSocketThread.ThreadPool.Count<>0 do Sleep(55);
  tcp_parser.Close;
end;

procedure TFParser.tcp_parserGetThread(Sender: TObject;
  var ClientSocketThread: TClientSocketThread);
begin
  ClientSocketThread:=TAuThread.Create(tcp_parser.ServerSocketThread);
  ClientSocketThread.FreeOnTerminate:=True;
  ClientSocketThread.Priority:=tpLowest;
end;

procedure TFParser.tcp_parserAccept(Sender: TObject;
  ClientSocket: TCustomIpClient);
begin
  with (ClientSocket.GetThreadObject as TAuThread) do
  begin
    atPacket:='c';
    ExecuteSyncProc;
    while not Terminated do
    begin
      atPacket:=ClientSocket.Receiveln;
      Application.ProcessMessages;
      if atPacket<>'c' then ExecuteSyncProc;
    end;
  end;
end;

procedure TAuThread.SyncProc;
begin
  if atPacket='c' then//connect
  begin
    Inc(DevCount);
    FParser.status_dev.SimpleText:='Connected Devices: '+IntToStr(DevCount);
    Application.ProcessMessages;
  end;
  if atPacket='d' then//disconnect
  begin
    Terminate;
    Dec(DevCount);
    FParser.status_dev.SimpleText:='Connected Devices: '+IntToStr(DevCount);
    Application.ProcessMessages;
  end;
  if atPacket[1]='#' then
  begin
    FParser.Memo1.Lines.Add(atPacket);
    Application.ProcessMessages;
  end
end;
проверил, закрывается тихо, без ошибок. Кто что думает?
"ковыряю изнутри" (с)

Последний раз редактировалось 3D Hunter; 27.07.2010 в 10:44. Причина: дополнение
3D Hunter вне форума Ответить с цитированием
Старый 27.07.2010, 14:01   #6
3D Hunter
Сумрачная тень
Форумчанин
 
Аватар для 3D Hunter
 
Регистрация: 05.03.2009
Сообщений: 689
По умолчанию

Не, ну так не пойдет. Народ, не спим. Первый вопрос остается в силе.
Теперь о втором вопросе. Код, представленный во 2м посте, заставляет приложение сдохнуть. Оно подвисает и ниуя не делает. Есть предположение, что после приема ReceiveLn клиент не может отослать данные. Может использовать свойство Receiving? Т.е. проверять вайлом, пока клиент в режиме приема, то нельзя отсылать пакеты. Или я не прав и на блокирующие сокеты это свойство не пашет?

Исходники в первом посте. Ссылка прямая. Жду подсказок и советов. Пожалуйста

Кстати, Свойство TCPServer.Close заставляет умереть переменную касса TServerSocketThread. Но не факт, что при уничтожении этого потока уничтожатся все его нити-сокеты. По крайней мере, в коде vcl такого не нашел
"ковыряю изнутри" (с)

Последний раз редактировалось 3D Hunter; 27.07.2010 в 14:04. Причина: дополнение
3D Hunter вне форума Ответить с цитированием
Старый 27.07.2010, 14:11   #7
mss
Заблокирован
 
Регистрация: 27.05.2010
Сообщений: 1,099
По умолчанию

procedure TFParser.tcp_parserAccept(Sender: TObject;
ClientSocket: TCustomIpClient);
begin
.. Application.ProcessMessages;


Это что за ересь ?
Какого черта ты в доп.треде обращаешься к потоконебезопасному объекту Application ?

> Свойство TCPServer.Close заставляет умереть переменную касса TServerSocketThread.

Не "умереть", а "разрушить объеат классаTServerSocketThread, ссылка на который хранится в приватном поле объекта".


> не факт, что при уничтожении этого потока уничтожатся все его нити-сокеты

Не факт. Особенно если поточные процедуры нитей реализованы криво.

Последний раз редактировалось Stilet; 27.07.2010 в 16:55.
mss вне форума Ответить с цитированием
Старый 27.07.2010, 16:40   #8
3D Hunter
Сумрачная тень
Форумчанин
 
Аватар для 3D Hunter
 
Регистрация: 05.03.2009
Сообщений: 689
По умолчанию

к примеру, каждый сокетный поток должен записывать всю приходящую информацию в текстовый файл. Проблема возникает при выходе из программы. Метод TCPServer.ClearThreadPool сигнализирует всем потокам, что пора завершаться, и каждый поток не дописывает пришедший последний пакет до конца в файл, а только часть! Но ведь свойство Terminated проверяется в цикле, а этот метод устанавливает его в тру. А в цикле как раз и происходит запись в файл. Вроде должно все записываться.
mss, если вы знаете решение этой проблемы, укажите пожалуйста в приведенном коде на мои ошибки. А так только критикуете.
Про Application.ProcessMessages учту.
"ковыряю изнутри" (с)
3D Hunter вне форума Ответить с цитированием
Старый 27.07.2010, 17:06   #9
mss
Заблокирован
 
Регистрация: 27.05.2010
Сообщений: 1,099
По умолчанию

> свойство Terminated проверяется в цикле

Оно у тебя проверяется до/после блокирующего вызова ReceiveLn(), так что ничто не мешает после обнаружения Terminated = True прервать цикл с опросом флага Terminated и ДО выхода из поточной процедуры "дочитать" остаток доступной для чтения инф-ции циклическим вызовом ReceiveLn(), пока он не вернет пустую строку.

Хотя здесь ждет засада - партнер по инф.обмену на другом конце соединения может уйти "покурить" на неопред.время, не разорвав соединение и не послав терминатор строки, что приведет к блокировке принимающего сокетного потока сервера на очер.вызове ReceiveLn на неопред.время. Что, в свою очередь, сделает невозможным корректное завершение работы TCPServer в ожидаемое время.
mss вне форума Ответить с цитированием
Старый 27.07.2010, 17:16   #10
3D Hunter
Сумрачная тень
Форумчанин
 
Аватар для 3D Hunter
 
Регистрация: 05.03.2009
Сообщений: 689
По умолчанию

патртнер по соединению - прибор, посылающий пакет раз в секунду и ждущий ответа сервера определенной строки 'ACCEPT r/n/'. Если прибор не получает подтверждения более 2 мин, то разрывает связь, после чего через 5мин стучится заново. При этом за время оффлайна он копит все данные приходящие раз в секунду. Т.е. при следующем соединении он перешлет инфу 1м пакетом за 7 мин.
"ковыряю изнутри" (с)
3D Hunter вне форума Ответить с цитированием
Ответ


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



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
[Delphi] TCPserver, TCPclient MASSIOMO Работа с сетью в Delphi 14 29.07.2010 17:53
TCPServer, TCPClient seobot Общие вопросы Delphi 2 03.05.2010 23:56
TCPClient, TCPServer : SendBufer() Zeraim Работа с сетью в Delphi 4 27.12.2009 21:22
TcpClient и TcpServer DOLBY Работа с сетью в Delphi 5 17.12.2007 10:43
TCPServer и TCPClient Antoha Работа с сетью в Delphi 19 06.10.2007 12:01