попробую приложить пример чуть попозже.
------------ Дoбавленo в 07.19:
Всем привет. Короче всё оказалось совсем всё интересно. Поэтому решил всё написать небольшую историю, потомкам на будущее и разработчикам на заметку, так как считаю что ошибка в компонентах (по возможности перенесите тему в категорию "Ошибки компонентов").
Напомню о постановке задаче и о самой проблеме:
Нужно было создать клиент серверное приложение, клиентов более 1000 шт. Решено было использовать TCP_Server и TCP_Client с DataType = dtStream, и Convertor для конвертации данных из dtStream в dtString. Клиенты должны отсылать кое какие данные на сервер, когда сервер становится не доступен, клиенты пытаются вновь подключиться. И вот возникла ошибка, когда все клиенты разом подключаются к серверу и отсылают данные после временной недоступности сервера, сервер воспринимает небольшое количество данных а потом виснет, хотя продолжает подключать к себе новых клиентов.
Для того что бы понять суть проблемы решил написать тестовые программы. Клиентская программа эмитировала 3000 подключений и отсылала данные на сервер.
Серверная часть:
Add(MainForm,2953706,343,161)
{
Width=385
Height=330
Caption="Server"
Position=1
Point(onClose)
link(onCreate,825948:doOpen,[])
link(onClose,825948:doClose,[])
}
Add(Label,1776579,637,245)
{
Left=20
Top=245
Width=200
}
Add(Label,7230009,511,266)
{
Left=20
Top=220
Width=200
}
Add(StrCat,7196014,469,266)
{
Str2=" Количество подключенных"
link(onStrCat,7230009:doText,[])
link(Str1,825948:Count,[(475,236)(412,236)])
}
Add(StrCat,15327132,595,245)
{
Str2=" Количество присланных"
link(onStrCat,1776579:doText,[])
link(Str1,11960055:Count,[])
}
Add(Convertor,3413582,539,175)
{
Mode=11
DirectFill=1
link(onResult,11960055:doAdd,[])
}
Add(Memo,11960055,588,175)
{
Left=15
Top=15
Width=335
Height=190
ScrollBars=3
link(onChange,15327132:doStrCat,[(634,181)(634,226)(583,226)(583,251)])
}
Add(TCP_Server,825948,406,175)
{
Port=1547
DataType=3
Point(doSendByIp)
link(onRead,3413582:doConvert,[])
link(onConnect,13372437:doEvent1,[])
link(onDisconnect,13372437:doEvent2,[])
}
Add(Hub,13372437,448,182)
{
InCount=2
OutCount=1
link(onEvent1,7196014:doStrCat,[(469,188)])
}
Клиентская часть:
Add(MainForm,2953706,266,385)
{
Width=264
Height=145
Caption="Client"
Position=1
}
Add(Button,8952864,280,497)
{
Left=75
Top=40
Width=135
Caption="Создать клиентов"
link(onClick,13120155:doCompare,[])
}
Add(Edit,6520318,476,455)
{
Left=10
Top=40
Hint="Количество клиентов"
Text="3000"
}
Add(For,16201031,469,504)
{
link(onEvent,4157259:##add,[])
link(End,6520318:Text,[])
}
Add(MultiElementEx,4157259,595,504)
{
Mode=1
link(IP,11266026:Var3,[(601,446)])
}
BEGIN_SDK
Add(EditMultiEx,3022714,21,21)
{
WorkCount=#5:##add|7:##clear|
VarCount=#7:##count|
DataCount=#2:IP|
Width=867
Height=298
Point(##add)
Point(##clear)
Point(##count)
link(##add,1465170:doValue,[(59,27)(59,83)])
}
Add(TCP_Client,11433968,287,126)
{
Port=1547
DataType=3
link(onConnect,1953504:doStrCat,[])
link(IP,3022714:IP,[(293,74)(27,74)])
}
Add(Timer,8884694,182,126)
{
Interval=1
link(onTimer,7644262:doCompare,[])
}
Add(If_else,7644262,231,126)
{
Op2=Integer(0)
link(onTrue,11433968:doOpen,[])
link(Op1,11433968:Active,[(237,114)(265,114)(265,170)(293,170)])
}
Add(Memory,1465170,343,77)
{
}
Add(StrCat,1953504,343,133)
{
Str2=" - Тестовый текст Очень длинный и сложный, что бы проверить всё на верняка. Тестовый текст Очень длинный и сложный, что бы проверить всё на верняка."
link(onStrCat,3413582:doConvert,[])
link(Str1,1465170:Value,[])
}
Add(Convertor,3413582,392,133)
{
Mode=12
link(onResult,11433968:doSend,[(441,139)(441,189)(275,189)(275,146)])
}
END_SDK
Add(Button,9240195,463,548)
{
Left=75
Top=65
Width=135
Caption="Удалить клиентов"
link(onClick,4157259:##clear,[(545,554)(545,517)])
}
Add(Edit,13472982,329,385)
{
Left=10
Top=15
Width=200
Hint="IP адрес сервера"
Text=""
}
Add(StrMask,13120155,329,497)
{
Mask="*.*.*.*"
link(onFalse,9845159:doMessage,[(377,503)(377,468)])
link(onTrue,16201031:doFor,[])
link(Str,11266026:Var2,[])
}
Add(Message,9845159,392,462)
{
Message="Укажите IP адрес сервера"
}
Add(GetDataEx,11266026,329,441)
{
link(Data,13472982:Text,[])
}
Для имитирования реальных условий, серверную часть программы нужно запускать после запуска 3000 клиентов, которые ждут доступности сервера, и при первой возможности, одновременно подключаться и отправят данные.
Если запустить серверную и клиентскую часть на одном компьютере то всё нормально отрабатывает, все 3000 пользователей подключаются и присылают данные.
Решено было клиентскую часть перенести на соседний компьютер, который находится в одной сети с основным компьютером.
И вот тут та сработала ошибка, которая срабатывала в реальных условиях. Приходили первые данные от первых подключенных пользователях и после конвертации элементом Converter часть из них отображалось, после Convertor походу путался в очереди и выдавал непонятный символ и зависал, хотя остальные пользователи продолжали успешно подключаться и присылать данные.
Началось стадия выяснения проблемы.
Опытным путём было выявлено: что при DataType = dtString в TCP_Server и TCP_Client и соответственно без Convertor, всё отлично работает. Пример:
Серверная часть DataType = dtString:
Add(MainForm,2953706,343,161)
{
Width=385
Height=330
Caption="Server"
Position=1
Point(onClose)
link(onCreate,825948:doOpen,[])
link(onClose,825948:doClose,[])
}
Add(Label,1776579,637,245)
{
Left=20
Top=245
Width=200
}
Add(Label,7230009,511,266)
{
Left=20
Top=220
Width=200
}
Add(StrCat,7196014,469,266)
{
Str2=" Количество подключенных"
link(onStrCat,7230009:doText,[])
link(Str1,825948:Count,[(475,236)(412,236)])
}
Add(StrCat,15327132,595,245)
{
Str2=" Количество присланных"
link(onStrCat,1776579:doText,[])
link(Str1,11960055:Count,[])
}
Add(Memo,11960055,588,175)
{
Left=15
Top=15
Width=335
Height=190
ScrollBars=3
link(onChange,15327132:doStrCat,[(634,181)(634,226)(583,226)(583,251)])
}
Add(TCP_Server,825948,406,175)
{
Port=1547
Point(doSendByIp)
link(onRead,11960055:doAdd,[])
link(onConnect,13372437:doEvent1,[])
link(onDisconnect,13372437:doEvent2,[])
}
Add(Hub,13372437,448,182)
{
InCount=2
OutCount=1
link(onEvent1,7196014:doStrCat,[(469,188)])
}
Клиентская часть DataType = dtString:
Add(MainForm,2953706,266,385)
{
Width=264
Height=145
Caption="Client"
Position=1
}
Add(Button,8952864,280,497)
{
Left=75
Top=40
Width=135
Caption="Создать клиентов"
link(onClick,13120155:doCompare,[])
}
Add(Edit,6520318,476,455)
{
Left=10
Top=40
Hint="Количество клиентов"
Text="3000"
}
Add(For,16201031,469,504)
{
link(onEvent,4157259:##add,[])
link(End,6520318:Text,[])
}
Add(MultiElementEx,4157259,595,504)
{
Mode=1
link(IP,11266026:Var3,[(601,446)])
}
BEGIN_SDK
Add(EditMultiEx,3022714,21,21)
{
WorkCount=#5:##add|7:##clear|
VarCount=#7:##count|
DataCount=#2:IP|
Width=867
Height=298
Point(##add)
Point(##clear)
Point(##count)
link(##add,1465170:doValue,[(59,27)(59,83)])
}
Add(TCP_Client,11433968,287,126)
{
Port=1547
link(onConnect,1953504:doStrCat,[])
link(IP,3022714:IP,[(293,74)(27,74)])
}
Add(Timer,8884694,182,126)
{
Interval=1
link(onTimer,7644262:doCompare,[])
}
Add(If_else,7644262,231,126)
{
Op2=Integer(0)
link(onTrue,11433968:doOpen,[])
link(Op1,11433968:Active,[(237,114)(265,114)(265,170)(293,170)])
}
Add(Memory,1465170,343,77)
{
}
Add(StrCat,1953504,343,133)
{
Str2=" - Тестовый текст Очень длинный и сложный, что бы проверить всё на верняка. Тестовый текст Очень длинный и сложный, что бы проверить всё на верняка."
link(onStrCat,11433968:doSend,[(384,139)(384,187)(275,187)(275,146)])
link(Str1,1465170:Value,[])
}
END_SDK
Add(Button,9240195,463,548)
{
Left=75
Top=65
Width=135
Caption="Удалить клиентов"
link(onClick,4157259:##clear,[(545,554)(545,517)])
}
Add(Edit,13472982,329,385)
{
Left=10
Top=15
Width=200
Hint="IP адрес сервера"
Text=""
}
Add(StrMask,13120155,329,497)
{
Mask="*.*.*.*"
link(onFalse,9845159:doMessage,[(377,503)(377,468)])
link(onTrue,16201031:doFor,[])
link(Str,11266026:Var2,[])
}
Add(Message,9845159,392,462)
{
Message="Укажите IP адрес сервера"
}
Add(GetDataEx,11266026,329,441)
{
link(Data,13472982:Text,[])
}
Далее было решено вернуть DataType = dtStream, так как того требовала основная задача. Далее заменил элемент в серверной части TCP_Server на TCP_ServerEx.
Серверная часть TCP_ServerEx:
Add(MainForm,2953706,343,161)
{
Width=385
Height=330
Caption="Server"
Position=1
Point(onClose)
link(onCreate,7089171:##open,[])
link(onClose,7089171:##Close,[])
}
Add(Label,1776579,637,245)
{
Left=20
Top=245
Width=200
}
Add(Label,7230009,511,266)
{
Left=20
Top=220
Width=200
}
Add(StrCat,7196014,469,266)
{
Str2=" Количество подключенных"
link(onStrCat,7230009:doText,[])
link(Str1,7089171:##Count,[(475,236)(412,236)])
}
Add(StrCat,15327132,595,245)
{
Str2=" Количество присланных"
link(onStrCat,1776579:doText,[])
link(Str1,11960055:Count,[])
}
Add(Memo,11960055,588,175)
{
Left=15
Top=15
Width=335
Height=190
ScrollBars=3
link(onChange,15327132:doStrCat,[(634,181)(634,226)(583,226)(583,251)])
}
Add(TCP_ServerEx,7089171,406,175)
{
ServerPort=1547
link(onRead,3413582:doConvert,[])
link(onEvent1,7196014:doStrCat,[(454,188)(454,272)])
}
BEGIN_SDK
Add(EditMultiEx,2650183,21,21)
{
WorkCount=#6:##open|7:##Close|
EventCount=#6:onRead|8:onEvent1|
VarCount=#7:##Count|
Point(##Count)
}
Add(TCP_Connection,12087566,189,105)
{
DataType=3
link(onRead,2650183:onRead,[(271,111)(271,27)])
link(onConnect,460347:doEvent1,[])
link(onDisconnect,460347:doEvent2,[])
}
Add(Hub,460347,259,112)
{
InCount=2
OutCount=1
link(onEvent1,2650183:onEvent1,[(297,118)(297,34)])
}
END_SDK
Add(Convertor,3413582,539,175)
{
Mode=11
DirectFill=1
link(onResult,11960055:doAdd,[])
}
Клиентская часть аналогична из первого примера:
И о чудо! Всё работает!
Выявлено, что при условиях:
1) TCP_Server с DataType = dtStream;
2) TCP_Server + Convertor;
3) Работа через сеть.
Возникает странная ошибка (как мне показалось зависание элемента Convertor). Хотя при использовании TCP_ServerEx вместо TCP_Server при таких же условиях ошибка не выдаётся и всё нормально функционирует.
Ну так как причина выявлена можно переходить к применению знаний к основной программе, но тут возникла загвозка. Как в элементе TCP_ServerEx отправлять данные для всех пользователей и для определённых по IP адресу (где взять точки doSend и doSendByIp у TCP_ServerEx аналогичные TCP_Server)? Является ли точка doSend в компоненте TCP_Connection аналогом как у TCP_Server?
Надеюсь разработчики обратят внимание на эти проблемы.
Комментируйте, обсуждайте, жду предложений и подсказок.