C++Builder
  Начало   Форум   Помощь Войти Регистрация  
Страниц: [1]   Вниз
  Печать  
Автор Тема: Как возвратить данные на форму из функции находящейся внутри потока  (Прочитано 2297 раз)
brdm
Участник


Сказали спасибо: +0/-0
Offline

Сообщений: 59


Как возвратить данные на форму из функции находящейся внутри потока
« : 27 Август 2014, 15:57:33 »

Попытки работы с функциями библиотеки WinPcap  обнаружили сильные тормоза на приеме данных из сети. Подозрение пало на неверное подключение функци приема пакетов в потоке. Поэтому создан небольшой тест в котором имеется
1. модуль формы Unit1
2. модуль потока Unit2
Модуль потока выглядит так: (прошу прощения что не в code C++  - иначе портятся комменты на русском)

#include
#pragma hdrstop
#pragma comment(lib,"wpcap.lib")
#pragma comment(lib,"Packet.lib");
#pragma comment(lib, "ws2_32.lib")
#include
#include
#include
#include "pcap.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include

#include "Unit2.h"
#include "Unit1.h"
#pragma package(smart_init)

int CntPack;

pcap_t *adhandle;

// Send_thread
char* packet;

// Строки
AnsiString StrMac, StrMacWt, StrPct;

// буфера
unsigned char shp[2000];

//---------------------------------------------------------------------------
// приемник пакетов

double *x,*y;
void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data)
{
  // вспомогательн.ф строкf
  AnsiString StrTmpPct;

  // строкf ожидаемого мак
   StrMac = "1c6f6542c220";
  // очистка проверочной строки мак
  StrMacWt = "";

   // запись входящего мак
   for(int i=0; i      StrMacWt += StrTmpPct.sprintf("%.2x", pkt_data);

   // проверка на входящий мак
  if(StrMacWt == StrMac)
   {
    CntPack++;

    for(unsigned int i=1; (i caplen + 1 ) ; i++)
    {
      // принятый пакет в массиве
      shp[i - 1] = pkt_data[i - 1];
      StrPct += StrTmpPct.sprintf("%.2x  ", shp[i - 1]);
    }
  }
//  Sleep(1);
}

//---------------------------------------------------------------------------

//   Important: Methods and properties of objects in VCL can only be
//   used in a method called using Synchronize, for example:
//
//      Synchronize(UpdateCaption);
//
//   where UpdateCaption could look like:
//
//      void __fastcall Unit2::UpdateCaption()
//      {
//        Form1->Caption = "Updated in a thread";
//      }
//---------------------------------------------------------------------------

__fastcall TRandomThread::TRandomThread(bool CreateSuspended)
  : TThread(CreateSuspended)
{
}
//---------------------------------------------------------------------------
void __fastcall TRandomThread::Execute()
{
  // назначить имя потоку
  SetThreadName(-1, "TRandomThread");
  // освободить занятую потоком память по окончании его работы
  FreeOnTerminate = true;
  // Создать объект класса
  ThreadExParams = new TThreadExParams();
  if(!ThreadExParams)
  {
    ShowMessage("Error");
    Application->Terminate();
  }
  // Прием пакетов
  pcap_loop(adhandle, 0, packet_handler, NULL);

  Sleep(1);

}

Его хедер:

Код
#ifndef Unit2H
#define Unit2H
//---------------------------------------------------------------------------
#include
//---------------------------------------------------------------------------
class TThreadExParams
{
public:
 bool Cl_Stop;
 int Cl_B;
};
 
class TRandomThread : public TThread
{
private:
protected:
 void __fastcall Execute();
public:
 __fastcall TRandomThread(bool CreateSuspended);
 AnsiString A;
 bool Stop;
 char ThreadPar1;
 int ThreadResult;
 int ThreadResultSum;
 int B;
 
 TThreadExParams *ThreadExParams;
};
//---------------------------------------------------------------------------
#define MS_VC_EXCEPTION 0x406d1388
typedef struct tagTHREADNAME_INFO
{
DWORD dwType; // must be 0x1000
LPCSTR szName; // pointer to name (in same addr space)
DWORD dwThreadID; // thread ID (-1 caller thread)
DWORD dwFlags; // reserved for future use, most be zero
} THREADNAME_INFO;
void SetThreadName(DWORD dwThreadID, LPCTSTR szThreadName)
{
THREADNAME_INFO info;
info.dwType = 0x1000;
info.szName = szThreadName;
info.dwThreadID = dwThreadID;
info.dwFlags = 0;
__try
{
RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(DWORD), (DWORD *)&info);
}
__except (EXCEPTION_CONTINUE_EXECUTION)
{
}
}
//---------------------------------------------------------------------------
#endif
 

И кусок Unit1:

#include
#pragma hdrstop
#pragma comment(lib,"wpcap.lib")
#pragma comment(lib,"Packet.lib");
#pragma comment(lib, "ws2_32.lib")
#include
#include
#include
#include "pcap.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include

#include "Unit1.h"
#include "Unit2.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma link "CSPIN"
#pragma resource "*.dfm"
TForm1 *Form1;
TRandomThread *Thread;
char Form1Par1 = 2;
int Form1Result;
int Form1ResultSum;
int Form1CntReseivePcap;

// флаг приема одного пакета
bool StepOne;
// номер прохода таймера
int NbSentPacket = 1;

// pcap tools
pcap_if_t *alldevs;
pcap_if_t *d;
pcap_t *adhandle;
int i_p;
char errbuf[PCAP_ERRBUF_SIZE];

// Send_thread
char* packet;

//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
  : TForm(Owner)
{
  Thread = new TRandomThread(true);
  if(!Thread)
  {
    ShowMessage("Error");
    Application->Terminate();
  }
  Edit1->Text = "2";
  Edit2->Text = "2";

  Sleep(50);
  if (pcap_findalldevs(&alldevs, errbuf) == -1)
   {
    Memo1->Lines->Add("Невозможно установить соеденение");
  }
   else
  {
    Memo1->Lines->Add("программа открыта");
  }
  for(d=alldevs;d;d=d->next)
   {
    ++i_p;
    ComboBox1->Items->Add(IntToStr(i_p)+ " " + d->description);
   }

.....

Подскажите пожалуйста как вывести на форму (модуль Unit1) хотя-бы значение счетчика принятых пакетов CntPack который находится  в функции принятия пакетов  packet_handler(...)? Как выводить на форму другие данные из функции пойму по ходу. 
Записан
OVE
Участник


Сказали спасибо: +67/-0
Offline

Сообщений: 72


Re: Как возвратить данные на форму из функции находящейся внутри потока
« Ответ #1 : 27 Август 2014, 16:16:37 »

Можно из потока (из функции packet_handler) посылать в форму сообщение через PostMessage. В качестве lParam и wParam указывать передаваемые данные.
PostMessage(Form1->Handle,WM_USER+1,1,CntPack)

А в модуле формы ловить это сообщение и спокойно выводить на форму передаваемые через lParam и wParam данные
Записан
brdm
Участник


Сказали спасибо: +0/-0
Offline

Сообщений: 59


Re: Как возвратить данные на форму из функции находящейся внутри потока
« Ответ #2 : 27 Август 2014, 17:13:35 »

Не в курсе как работать с PostMessage.
Если можно в двух словах как это сделать для данного случая.
Переменные из потока я передавал так:
В потоке: (Unit2.cpp)
Код
      ThreadResultSum = ...;
 
Хедер потока:
Код
.....
class TThreadExParams
{
public:
 bool Cl_Stop;
 int Cl_B;
};
 
class TRandomThread : public TThread
{
private:
protected:
 void __fastcall Execute();
public:
 __fastcall TRandomThread(bool CreateSuspended);
 AnsiString A;
 bool Stop;
 char ThreadPar1;
 int ThreadResult;
 int ThreadResultSum;
 int B;
....
 
 
В форме: (Unit1.cpp)
Код
...
int Form1ResultSum;
...
Form1ResultSum = Thread->ThreadResultSum;

 


 
Записан
serg76
Участник


Сказали спасибо: +38/-2
Offline

Сообщений: 575


Re: Как возвратить данные на форму из функции находящейся внутри потока
« Ответ #3 : 27 Август 2014, 17:52:22 »

Цитировать
Переменные из потока я передавал так:
точно так же можно обращаться из потока к компанентам на форме, но через Synchronize и если не критичны задержки до 15 мл.сек
Код
void __fastcall TRandomThread::vzl()
{
Form1->Edit1->Text = "2";
}
 
.....
 
while(!Terminated)
{
 Synchronize(vzl);
}


Да и в Execute() должен быть цикл while(!Terminated)
Записан
brdm
Участник


Сказали спасибо: +0/-0
Offline

Сообщений: 59


Re: Как возвратить данные на форму из функции находящейся внутри потока
« Ответ #4 : 27 Август 2014, 18:39:16 »

Пока не врубился.

Вот цикл в потоке:
Код
  while(!Terminated)
 {
   pcap_loop(adhandle, 0, packet_handler, NULL);
 
   Sleep(1);
 }
 
pcap_loop - функция которая ловит пакеты.
Это функция котрая обрабатывает принятые пакеты
void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data)
{
  // вспомогательн.строка
  AnsiString StrTmpPct;

  // строкf ожидаемого мак
   StrMac = "1c6f6542c220";
  // очистка проверочной строки мак
  StrMacWt = "";

   // запись входящего мак
   for(int i=0; i      StrMacWt += StrTmpPct.sprintf("%.2x", pkt_data);

   // проверка на входящий мак
  if(StrMacWt == StrMac)
   {
    CntPack++;
    PostMessage(Form1->Handle,WM_USER+1,1,CntPack);
  }
}
Нужно передать на форму CntPack.
Что такое WM_USER+1? Как в этом случае выглядит строка приема CntPack (например в Label1) в модуле формы. Что нужно записать в хедере модуля потока и модуля формы для PostMessage?  

Если через  Synchronize то как это выглядит в коде для каждого модуля и их хедеров?
Записан
OVE
Участник


Сказали спасибо: +67/-0
Offline

Сообщений: 72


Re: Как возвратить данные на форму из функции находящейся внутри потока
« Ответ #5 : 27 Август 2014, 22:31:25 »

WM_USER - это константа, начиная с которой можно посылать пользовательские сообщения.
В h-файле класса формы объявляешь функцию-обработчик сообщения WM_USER+1 (можешь и WM_USER+500)
Код:
class TForm1 : public TForm
{
__published: // IDE-managed Components
   TLabel *Label1;
private: // User declarations
   void __fastcall OnWM_USER1(TMessage &Msg);
public: // User declarations
   __fastcall TForm1(TComponent* Owner);
BEGIN_MESSAGE_MAP
   VCL_MESSAGE_HANDLER(WM_USER+1, TMessage, OnWM_USER1);
END_MESSAGE_MAP(TForm)
};

А в cpp-файле реализуешь эту функцию
Код:
void __fastcall TForm1::OnWM_USER1(TMessage &Msg)
{
   if(Msg.WParam==1)
      Label1->Caption=IntToStr(Msg.LParam);
   //здесь в WParam будет 1 , а в LParam будет CntPack
}
Записан
brdm
Участник


Сказали спасибо: +0/-0
Offline

Сообщений: 59


Re: Как возвратить данные на форму из функции находящейся внутри потока
« Ответ #6 : 28 Август 2014, 00:04:06 »

Спасибо. Работает.
Но проблема в том, что таким образом передается переменная CntPack из потока, тоесть
типа 
Код
void __fastcall TRandomThread::Execute()
{
.....
while(!Terminated )
 {
   CntPack++;
   PostMessage(Form1->Handle,WM_USER+1,1,CntPack);
  }
....

В моем случае в поток включена функция ловли пакетов pcap_loop(adhandle, 0, packet_handler, NULL); типа
Код
void __fastcall TRandomThread::Execute()
{
.....
pcap_loop(adhandle, 0, packet_handler, NULL);
которя сама по себе представляет бесконечный цикл, которая в свою очередь включает в себя функцию обработки пакетов типа
Код
void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data)
{
...
CntPack++;
Из этой функции нужно передать на форму CntPack
Если поместить в функцию PostMessage(Form1->Handle,WM_USER+1,1,CntPack);
ошибки нет, но и передачи нет.
Замкнутый круг. Не знаю че делать...
 
Записан
OVE
Участник


Сказали спасибо: +67/-0
Offline

Сообщений: 72


« Ответ #7 : 28 Август 2014, 00:23:44 »

Для начала я бы убедился, что мы попадаем в функцию packet_handler и PostMessage действительно вызывается.
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  




....

Powered by SMF 1.1.21 | SMF © 2025, Simple Machines
Страница сгенерирована за 0.096 секунд. Запросов: 21.