![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Помогите найти компоненты для TCP... :) [D5, Win2k]
Terminus © (2003-08-25 16:39:00)
Господа! Сможет ли кто-нибудь посоветовать хорошие компоненты/модули для реализации TCP клиента/сервера? Сие необходимо для создания мультиплеера в игрухе... :)
Только, плз, не предлагать 2 варианта:
1. Писать самому.
2. THxTcpIpcUdp. Хороший модуль, но то, что код, перенесенный из стандартного примера в игру, перестал работать (невозможно добиться пересылки record) окончательно вывело меня из себя. :) Жаль...
Еще буду благодарен, если кто объяснит принципиальное отличие сервера синхронного и асинхронного. Литературу в INet"е почитал, но практической разницы так и не понял. :)
Заранее благодарен.
Terminus (2003-08-25 20:50:00) [1]
Еще раз спасибо. :) Помещаю теперь в TByteArray и после доставки собираю обратно в record...
Еще. Предполагается, что пакеты, по большей части, будут небольшими (несколько десятков байт), но серверу прийдется рассылать все это десяткам клиентов (как минимум) и весьма часто... Поэтому и хотелось ускорить процедуры пересылки... Хотя может, зря все это, мелочи...
Reindeer Moss Eater (2003-08-25 19:36:00) [2]
В общем, хотелось бы не утяжелять прогу всем этим
Надо очень сильно попотеть, что бы утяжелить свою прогу кодом (именно кодом).
Terminus (2003-08-25 18:59:00) [3]
[i]To Dimka Maslov[/i]
Спасибо, посмотрю, буду пробовать...
[i]To Reindeer Moss Eater
Почему извращение? Потому что требует дополнительного программирования нескольких строк?[/i]
В общем, хотелось бы не утяжелять прогу всем этим, но, похоже, иного выхода нет. :) Ладно, спасибо всем за помощь, пойду эксперементировать...
Reindeer Moss Eater (2003-08-25 18:47:00) [4]
Так все таки, как организовать пересылку record структур?
Не в самих Record"ах проблема, а в Record"ах, имеющих указатели.
Dimka Maslov (2003-08-25 18:45:00) [5]
>Terminus
Зайди на http://icq2000cc.hobi.ru/там подробно описано как организовать пересылку записей со строками переменной длины.
Reindeer Moss Eater (2003-08-25 18:42:00) [6]
Так все таки, как организовать пересылку record структур? Можно, конечно, перед пересылкой запихивать содержимое record в текий буфер, и кидать уже его, а на другом конце опять заносить в record, но это уже извращение... :(
Почему извращение? Потому что требует дополнительного программирования нескольких строк?
Reindeer Moss Eater (2003-08-25 18:41:00) [7]
Характерно, что если и сервер и клиент размещаются в одном модуле (в пресловутом стандартном примере), этот же код работает. Я вижу две причины, обе из которых мне не нравятся. :)
Указатель переданный клиенту, продолжает указывать на то место в памяти, куда он указывал до своего путешествия к клиенту.
Вот и все "характерно"
Dimka Maslov (2003-08-25 18:39:00) [8]
>Polevi
Скорость работы клиента при множественном подключении клиентов к серверу меньше если сервер работает в синхронном режиме именно за счёт ожидания, особенно если запрос приводит к передаче больших массивов данных. При небольшом объёме отправляемых пакетов замедление работы клиента не столь существенно.
>Terminus
TDecoreateInfo = record
RecordType: Byte;
RecordSize: LongInt;
Empty: LongInt;
NameLen: LongInt;
Name: array[0..0] of Char;
end;
Terminus (2003-08-25 18:37:00) [9]
И? Выход то где в этом случае? :)
Характерно, что если и сервер и клиент размещаются в одном модуле (в пресловутом стандартном примере), этот же код работает. Я вижу две причины, обе из которых мне не нравятся. :)
1. Две копии программы, запущенные паралельно, используют одну и ту же область памяти (что невозможно)
2. Причина бага в другом.
Так все таки, как организовать пересылку record структур? Можно, конечно, перед пересылкой запихивать содержимое record в текий буфер, и кидать уже его, а на другом конце опять заносить в record, но это уже извращение... :(
Reindeer Moss Eater (2003-08-25 18:26:00) [10]
TDecorateInfo = record
RecordType: Byte;
Empty: Integer;
Name: PChar;
end;
SvrTcp.SendData(PDecorate,SizeOf(Decorate),0);
При выполнении этого кода, поле Nameиз TDecorateInfo никуда не посылается. Вместо этого посылается значение указателя, который на приемном конце лишен всяческого смысла ибо указывает в космос.
Terminus (2003-08-25 17:48:00) [11]
unit Common;
{$DEFINE CLIENT}
{DEFINE SERVER}
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
HxTcpIpcUdp;
type
TForm1 = class(TForm)
procedure FormShow(Sender: TObject);
{$IFDEF SERVER}
procedure OnNewClient(iDescr: Integer);
{$ENDIF}
private
{ Private declarations }
public
{ Public declarations }
{$IFDEF CLIENT}
procedure HandleClientDataAvailable(ptr: pointer; iSize: integer);
{$ENDIF}
end;
THeroInfo = record
RecordType: Byte;
Name: PChar;
end;
TDecorateInfo = record
RecordType: Byte;
Empty: Integer;
Name: PChar;
end;
var
Form1: TForm1;
svrTCP: THxTcpServer;
clntTCP: THxTcpClient;
Hero: THeroInfo;
Decorate: TDecorateInfo;
PHero: ^THeroInfo;
PDecorate: ^TDecorateInfo;
implementation
{$R *.DFM}
{$IFDEF CLIENT}
procedure TForm1.HandleClientDataAvailable(ptr: pointer; iSize: integer);
var
s: string;
z,i,j: Integer;
oRecordType: Byte;
begin
Move(ptr^,oRecordType,1);
case oRecordType of
1: begin
Move(ptr^,Hero,isize);
ShowMessage(StrPas(Hero.Name));
end;
2: begin
Move(ptr^,Decorate,isize);
ShowMessage(StrPas(Decorate.Name));
end;
end;
end;
{$ENDIF}
procedure TForm1.FormShow(Sender: TObject);
begin
{$IFDEF SERVER}
svrTCP := THxTcpServer.Create;
svrTCP.Port := "2003";
svrTCP.OnNewClient := OnNewClient;
svrTCP.Listen;
{$ENDIF}
{$IFDEF CLIENT}
clntTcp := THxTcpClient.Create;
clntTcp.ServerAddress := "localhost";
clntTcp.Port := "2003";
clntTcp.OnDataAvailable := HandleClientDataAvailable;
clntTcp.Connect;
{$ENDIF}
end;
{$IFDEF SERVER}
procedure TForm1.OnNewClient(iDescr: Integer);
begin
PHero:=@Hero;
PDecorate:=@Decorate;
PHero.RecordType:=1;
PDecorate.RecordType:=2;
PHero.Name:=PChar("Герой");
PDecorate.Name:=PChar("Декоративный объект");
SvrTcp.SendData(PDecorate,SizeOf(Decorate),0);
end;
{$ENDIF}
end.
Вот полный код неработующего модуля. Соответственно, для клиента компилируется один код, для сервера другой, но это неважно...
Суть в том, чт клиент по певому байту должен определить тип записи (и в видоизмененном стандартном примере исправно это делает) и вывести имя объекта. Разумеется, код тестовый, так что обращать внимание только на суть проблемы. :)
Reindeer Moss Eater (2003-08-25 17:22:00) [12]
Переношу код, ....
....
Вот такие пироги... :[
Ты не объясняй, что ты делаешь, ты код покажи.
Terminus (2003-08-25 17:11:00) [13]
To Dimka Maslov
Я так понимаю, синхронный сервер нужен тогда, когда мне важно, чтобы запросы обрабатывались в той последовательности, в какой были отправлены?
Terminus (2003-08-25 17:09:00) [14]
Тем, кто юзает HxTcpIpcUdp (поскольку альтернатив пока никто не предложил :)
Мда... Короче, видоизменил стандартный пример для отправки record, в составе которого есть PChar. Клиент запись отправляет, сервер принимает и отображает строку. Все нормально.
Переношу код, разделяя клиента и сервера в отдельные программы. Переменные svrTCP и clntTCP объявляю как отдельные переменные, вне TForm1. Сообщение отсылает теперь сервер клиенту. В результате, после получение записи клиентом вместо строки бред. Т.е. не бред, конечно, не явно содержимое некой другой области памяти, в которой моей строки нет. :) Вот такие пироги... :[
Reindeer Moss Eater (2003-08-25 16:51:00) [15]
Самое смешное, что отдельные переменные перекидываются (хотя бы та же SendString), а вот с record... В общем, вопрос остается в силе. :)
Тебе наверное попалась какая-то особо интеллектуальная библиотека, которая распознает что с помощью ее пытаются передать. Строки или записи. Она видимо байты внимательно разглядывает и находит 10 отличий.
Polevi (2003-08-25 16:49:00) [16]
>что уменьшает скорость
это кто тебе такое сказал
Terminus (2003-08-25 16:49:00) [17]
Попробую, но ... смешно. Код простой, инициализация и можно отправлять... Самое смешное, что отдельные переменные перекидываются (хотя бы та же SendString), а вот с record... В общем, вопрос остается в силе. :)
Dimka Maslov (2003-08-25 16:47:00) [18]
Лучше писать самому при помощи WinSock. Особых сложностей нет.
Синхронный сервер обрабатывает запросы клиентов последовательно в одном потоке, что уменьшает скорость и увеличивает надёжность, поскольку нет проблем с доступом к ресурсам, разделяемым между потоками. Асинхронный сервер при получении запроса клиента создаёт новый поток, который этот запрос и обрабатывает при увеличении скорости работы (клиент не ждёт завершения обработки других запросов) возникает серьёзная проблема доступа к разделяемым ресурсам при плохом решении которой программа часто получает конфликты доступа, которые не могут отловлены.
Reindeer Moss Eater (2003-08-25 16:46:00) [19]
Хороший модуль, но то, что код, перенесенный из стандартного примера в игру, перестал работать
А если перенести не в игру?