Форум программистов, компьютерный форум, киберфорум
C++ Builder
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.72/18: Рейтинг темы: голосов - 18, средняя оценка - 4.72
0 / 0 / 0
Регистрация: 25.06.2010
Сообщений: 36

TTCPServer и два потока

25.02.2011, 04:40. Показов 3865. Ответов 10
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Доброго времени суток, форумчане!

У меня появилась такая задачка: надо организовать получение и отправку данных через серверный сокет. В программе должно быть 2 потока: главный и поток для сокета. Для каждого пользователя создавать отдельный поток нельзя, так как выполняются не потоко-безопасные функции.
Я попробывал реализовать это через компонент TTcpServer, но как мне показал менеджер задач (Process Explorer), новый поток во время начала прослушки порта не создается, да и когда пользователь подключается - тоже нет нового потока. Судя по всему все работает в главном потоке, что меня не устраивает.

Вопросы:
  1. Как организовать такую работу.
  2. Возможно ли сделать очередь на подключение к сокету (чтобы работа с ним была синхронная, один клиент получил ответ - запрос второго клиента, из очереди, пошел на обработку).
  3. Где можно почитать как вообще это все работает, а то все эти коды примитивных чатов не позволяют мне узнать то, с чем у меня возникла проблема.
0
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
25.02.2011, 04:40
Ответы с готовыми решениями:

Два потока, две очереди, два потока
Есть две очереди. Каждая из них заполняется своим потоком. Есть два потока, которые достают данные из своей очереди. Но когда одна из...

Что будет, если два разных потока попытаются отправить одновременно одному клиенту два разных пакета
Здравствуйте! Имеется вот такой незамысловатый метод отправки пакетов на сокет клиента public static void...

TTcpServer, TTcpClient...
Сори за ламерство, но вот: (Желательно дать код или пример :) ) 1. послать байт от клиента серверу 2. прочитать его сервером

10
 Аватар для kzru_hunter
1124 / 795 / 101
Регистрация: 01.02.2011
Сообщений: 1,887
Записей в блоге: 1
25.02.2011, 08:06
Используй класс TThread. Пример из Rad Studio XE:
C++
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
bool mythreadRunning;
bool youthreadRunning;
 
class TMyThread : public TThread
{
__published:     IDE-managed Components
private:     User declarations
protected:   User declarations
 
    void __fastcall Execute();
public:     // User declarations
    __fastcall TMyThread(bool suspended);
};
 
__fastcall TMyThread::TMyThread(bool suspended)
    : TThread(suspended)
{
}
 
class TYouThread : public TThread
{
__published:    // IDE-managed Components
private:    // User declarations
protected:  // User declarations
    void __fastcall Execute();
public:     // User declarations
    __fastcall TYouThread(bool suspended);
};
 
__fastcall TYouThread::TYouThread(bool suspended)
    : TThread(suspended)
{
}
 
void __fastcall TMyThread::Execute()
{
  Form1->Memo1->Lines->Add("Process has been running for this many seconds:");
  for (int I = 0; I <= 10; I++)
  {
    Form1->Memo1->Lines->Add("Low priority process " + IntToStr(I));
    Sleep(1000);
  }
  mythreadRunning = FALSE;
}
 
void __fastcall TYouThread::Execute()
{
  Form1->Memo3->Lines->Add("Second low priority process has been running for this many seconds:");
  for (int I = 0; I <= 10; I++)
  {
    Form1->Memo3->Lines->Add("Second low priority process " + IntToStr(I));
    Sleep(1000);
  }
  youthreadRunning = FALSE;
}
 
void __fastcall TForm1::Button1Click(TObject *Sender)
{
  TMyThread *SecondProcess; // TMyThread is a custom descendant of TThread.
  if (mythreadRunning == FALSE)
  {
    mythreadRunning = TRUE;
    SecondProcess = new TMyThread(True); // Creation suspended--the second process does not run yet.
    SecondProcess->FreeOnTerminate = True; // No need to clean up after termination
    SecondProcess->Priority = tpLower;  // Set the priority to lower than normal.
    SecondProcess->Resume(); // Now run the thread.
  }
  else
    MessageDlg("This thread is still running. You are going to hurt yourself!",
      mtInformation, TMsgDlgButtons() << mbOK, 0);
}
 
void __fastcall TForm1::Button2Click(TObject *Sender)
{
  Form1->Memo2->Lines->Add("Do some work in the main process for 10 seconds:");
  for (int I = 0; I <= 10; I++)
  {
    Form1->Memo2->Lines->Add("Main process " + IntToStr(I));
    Sleep(1000);
  }
}
 
void __fastcall TForm1::Button3Click(TObject *Sender)
{
  TYouThread *SecondProcess; // TMyThread is a custom descendant of TThread.
  if (youthreadRunning == FALSE)
  {
    youthreadRunning = TRUE;
    SecondProcess = new TYouThread(True); // Creation suspended--the second process does not run yet.
    SecondProcess->FreeOnTerminate = True; // No need to clean up after termination
    SecondProcess->Priority = tpLower;  // Set the priority to lower than normal.
    SecondProcess->Resume(); // Now run the thread.
  }
  else
    MessageDlg("This thread is still running. You are going to hurt yourself!",
      mtInformation, TMsgDlgButtons() << mbOK, 0);
}
 
__fastcall TForm1::TForm1(TComponent* Owner)
  : TForm(Owner)
{
  mythreadRunning = FALSE;
  youthreadRunning = FALSE;
}
Для синхронизации используй метод Synchronize (также из справки):
C++
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
__fastcall TEnumeratorThread::TEnumeratorThread(TMemo* Memo)
    : TThread(true)
{
    /* Initialize internal fields */
    m_Memo = Memo;
    m_CurrNbr = 0;
    m_Stop = 0;
}
 
void __fastcall TEnumeratorThread::Execute()
{
    /* Repeat the loop until the flag says otherwise. */
    while (!m_Stop)
    {
        /* Wait for 100 milliseconds. */
        Sleep(100);
 
        /*
        Run the AddNewNumberToMemo procedure on the main thread.
        This makes it safe to access GUI from this thread.
        */
        Synchronize(AddNewNumberToMemo);
    }
 
    m_Stop = 0;
}
 
void __fastcall TEnumeratorThread::GentleStop()
{
  /* Set the flag to 1. */
  InterlockedIncrement(&m_Stop);
 
  /* Wait for this thread to finish executing */
  this->WaitFor();
}
 
void __fastcall TEnumeratorThread::AddNewNumberToMemo()
{
  /* Increase the current number and add it to the memo. */
  m_CurrNbr++;
  m_Memo->Lines->Add(IntToStr(m_CurrNbr));
}
1
0 / 0 / 0
Регистрация: 25.06.2010
Сообщений: 36
25.02.2011, 11:35  [ТС]
Дело в том, что я уже пытался создавать сокет в новом потоке в методе Execute. Я инициализировал его до цикла, и открыл соединение (фаерволом увидел, что мой поток начал прослушивать порт). Потом пробывал подключаться клиентом, но события подключения клиента так и не возникли. Поток как-будто занят итерациями цикла и не обращает внимание на прием событий подключения клиента.
Синхронизацию таким методом, который вы указали я не использую. В dll он не работает, поэтому у меня немного другой метод синхронизации.
0
 Аватар для kzru_hunter
1124 / 795 / 101
Регистрация: 01.02.2011
Сообщений: 1,887
Записей в блоге: 1
25.02.2011, 11:56
С потоками я не спец. Но если логически подумать, то в Execute не должно быть циклов, нужно вызвать его и выйти как можно скорее. А цикл обрабатывать с помощью таймера.
0
0 / 0 / 0
Регистрация: 25.06.2010
Сообщений: 36
25.02.2011, 11:59  [ТС]
Цитата Сообщение от kzru_hunter Посмотреть сообщение
С потоками я не спец. Но если логически подумать, то в Execute не должно быть циклов, нужно вызвать его и выйти как можно скорее. А цикл обрабатывать с помощью таймера.
Вот я же и написал топик, чтобы дали конкретных примеров по моему случаю...
0
 Аватар для kzru_hunter
1124 / 795 / 101
Регистрация: 01.02.2011
Сообщений: 1,887
Записей в блоге: 1
25.02.2011, 14:48
Вроде получилось. Ответ от клиента приходит в другом потоке.

CPP:
C++
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
//---------------------------------------------------------------------------
 
#include <vcl.h>
#pragma hdrstop
 
#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
TTcpServer *TcpServer1;
TThread *hMyThread;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
        : TForm(Owner)
{
        Form1->Memo1->Lines->Add( "Start, thread = " + (AnsiString)GetCurrentThreadId() );
 
        TcpServer1 = new TTcpServer(this);
        hMyThread = new TMyThreadClass(false);
}
//---------------------------------------------------------------------------
 
//---------------------------------------------------------------------------
 
//---------------------------------------------------------------------------
__fastcall TMyThreadClass::TMyThreadClass(bool suspended)
    : TThread(suspended)
{
        TcpServer1->BlockMode = bmThreadBlocking;
    TcpServer1->OnAccept = TcpServer1Accept;
    TcpServer1->OnCreateHandle = TcpServer1CreateHandle;
        TcpServer1->LocalPort = 6666;
    TcpServer1->Active = true;
}
//---------------------------------------------------------------------------
 
void __fastcall TMyThreadClass::Execute()
{
        // do something
}
 
void __fastcall TMyThreadClass::TcpServer1CreateHandle(TObject *Sender)
{
    TDateTime now = TDateTime::CurrentDateTime();
    Form1->Memo1->Lines->Add(DateTimeToStr(now) + " Server started. Thread = " + (AnsiString)GetCurrentThreadId());
}
 
void __fastcall TMyThreadClass::TcpServer1Accept(TObject *Sender, TCustomIpClient *ClientSocket)
{
        Form1->Memo1->Lines->Add( "Answer from client, thread = " + (AnsiString)GetCurrentThreadId() );
}
H:
C++
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
//---------------------------------------------------------------------------
 
#ifndef Unit1H
#define Unit1H
//---------------------------------------------------------------------------
#include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <Forms.hpp>
#include <Sockets.hpp>
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published:    // IDE-managed Components
        TMemo *Memo1;
private:    // User declarations
public:     // User declarations
        __fastcall TForm1(TComponent* Owner);
};
 
class TMyThreadClass : public TThread
{
__published:    // IDE-managed Components
private:    // User declarations
protected:  // User declarations
    void __fastcall Execute();
        void __fastcall TcpServer1CreateHandle(TObject *Sender);
        void __fastcall TcpServer1Accept(TObject *Sender, TCustomIpClient *ClientSocket);
public:     // User declarations
    __fastcall TMyThreadClass(bool suspended);
 
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif
0
0 / 0 / 0
Регистрация: 25.06.2010
Сообщений: 36
25.02.2011, 18:14  [ТС]
kzru_hunter, вот что вы сделали:
1. Выделили память для треда и тспсервера.
2. Тред запустился - открыл прослушку порта и сразу же остановился, так как в методе Execute пусто.
3. Так как тспсерверу был выставлено свойство BlockMode = bmThreadBlocking, то для каждого подключения создается отдельный тред.
4. В итоге толку от треда, который вы создали - 0. Вы попробуйте выставить свойство BlockMode в bmNonBlocking и увидите, что новый тред для клиента не создастся.

Мне не надо новый тред для каждого клиента, мне надо, чтобы прослушка и обработка запросов была в отдельном треде с очередью клиентов.
0
 Аватар для kzru_hunter
1124 / 795 / 101
Регистрация: 01.02.2011
Сообщений: 1,887
Записей в блоге: 1
25.02.2011, 19:08
TheSteelRat, проверял код?
Мне не надо новый тред для каждого клиента, мне надо, чтобы прослушка и обработка запросов была в отдельном треде с очередью клиентов.
всё в одном потоке обрабатывается, который был создан в самом начале.

Тред запустился - открыл прослушку порта и сразу же остановился, так как в методе Execute пусто.
нет, он будет работать, т.к. BlockMode = bmThreadBlocking

Добавлено через 48 минут
В инете узнал, что с этими компонентами не удобно работать. Поэтому лучше вместо них использовать TClientSocket и TServerSocket.
0
0 / 0 / 0
Регистрация: 25.06.2010
Сообщений: 36
25.02.2011, 20:30  [ТС]
kzru_hunter, я уже много чего перепробывал. bmThreadBlocking обозначает, что каждый клиент должен в отдельном потоке обрабатываться, и он нифига не блокирует тот поток, в котором щас находится, он блокирует те потоки, которые сам создаст. Он из созданного тобою потока выйдет сразу же после открытия прослушки и будет выполняться в основном потоке до подключения клиентов. Как только начнут подключаться клиенты - сразу наштампует потоков под каждого клиента.
Компоненты TClientSocket и TServerSocket являются устаревшими и мало чем отличаются от TTcpServer и TTcpClient...
0
 Аватар для kzru_hunter
1124 / 795 / 101
Регистрация: 01.02.2011
Сообщений: 1,887
Записей в блоге: 1
25.02.2011, 21:00
С этими компонентами только сегодня познакомился, поэтому многого не знаю.
Решил как-то помочь, т.к. тоже интересна тема.
Надеюсь, кто-нибудь поможет.

Насчет потоков хотел спросить: почему ThreadID показывает одинаковый, если подключаться с разных клиентов?
0
0 / 0 / 0
Регистрация: 25.06.2010
Сообщений: 36
25.02.2011, 22:31  [ТС]
kzru_hunter, функция GetCurrentThreadId получает скорее всего именно Id главного потока. Для того, чтобы получить id потока, который создал TcpServer надо обращаться к конкретной функции этого объекта, что-то типа ClientSocket->ThreadId...
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
25.02.2011, 22:31
Помогаю со студенческими работами здесь

два потока
Не могу найти простой пример, исходники находил но там как-то много лишнего. Может кто-нибудь показать полный код где бы в первом потоке...

Два потока winapi
Ребят ребят,два потока нужно сделать в проге,вот хотел узнать,это только через WINAPI можно сделать? Нет ли какого нибудь ещё хитрого и...

Создать два потока на с++
Создать два потока на языке программирования С + + в среде Borland C + + Builder с использованием функции WinAPI, первый из которых выводит...

Звук на два потока
Возможно ли каким-нибудь образом средствами 7ки сделать так, что бы на одни колонки выводился звук одного приложения, а на другие из...

Создать два потока
Всем, всем здравствуйте!!!! У меня такая возникла сложности нужно написать программу в которой, используя Winapi функции создаются два...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
11
Ответ Создать тему
Новые блоги и статьи
Настройки VS Code
Loafer 13.04.2026
{ "cmake. configureOnOpen": false, "diffEditor. ignoreTrimWhitespace": true, "editor. guides. bracketPairs": "active", "extensions. ignoreRecommendations": true, . . .
Оптимизация кода на разграничение прав доступа к элементам формы
Maks 13.04.2026
Алгоритм из решения ниже реализован на нетиповом документе, разработанного в конфигурации КА2. Задачи, как таковой, поставлено не было, проделанное ниже исключительно моя инициатива. Было так:. . .
Контроль заполнения и очистка дат в зависимости от значения перечислений
Maks 12.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "ПланированиеПерсонала", разработанного в конфигурации КА2. Задача: реализовать контроль корректности заполнения дат назначения. . .
Архитектура слоя интернета для сервера-слоя.
Hrethgir 11.04.2026
В продолжение https:/ / www. cyberforum. ru/ blogs/ 223907/ 10860. html Знаешь что я подумал? Раз мы все источники пишем в голове ветки, то ничего не мешает добавить в голову такой источник, который сам. . .
Подстановка значения реквизита справочника в табличную часть документа
Maks 10.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "ПланированиеПерсонала", разработанного в конфигурации КА2. Задача: при выборе сотрудника (справочник Сотрудники) в ТЧ документа. . .
Очистка реквизитов документа при копировании
Maks 09.04.2026
Алгоритм из решения ниже применим как для типовых, так и для нетиповых документов на самых различных конфигурациях. Задача: при копировании документа очищать определенные реквизиты и табличную. . .
модель ЗдравоСохранения 8. Подготовка к разному выполнению заданий
anaschu 08.04.2026
https:/ / github. com/ shumilovas/ med2. git main ветка * содержимое блока дэлэй из старой модели теперь внутри зайца новой модели 8ATzM_2aurI
Блокировка документа от изменений, если он открыт у другого пользователя
Maks 08.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа, разработанного в конфигурации КА2. Задача: запретить редактирование документа, если он открыт у другого пользователя. / / . . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru