Модераторы: Snowy, Poseidon, MetalFan
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Сетевая игра 
:(
    Опции темы
Toland2
Дата 8.11.2011, 21:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 22
Регистрация: 11.10.2011

Репутация: нет
Всего: нет



Уважаемые программисты, помогите пожалуйста разобраться с одной проблемой.
Я задумал сделать очень простую сетевую игру танчики.

В клиенте создается TImage с изображением танка 
(Tank:array [1..10] of TImage;), его номер отправляется 
на сервер и рассылается всем подключенным клиентам. 
И на тех клиентах создаются TImage с таким же номером.

В клиенте передвигаю TImage по форме, её кординаты
передаются на сервер и рассылаются всем подключенным клиентам.
У меня есть вот такая структура, которую я передаю через сокеты:
Код

   type
    PlayerPosition = packed record
      PosX:integer; //Положение по X
      PosY:integer; //Положение по Y
      id:integer;   //id танка
  end;

Сначала эта структура попадает на сервер и он рассылает её всем 
клиентам вот таким образом:
Код

procedure TForm1.SendPosTank;
var 
i: integer;
Pos:PlayerPosition;
begin
  for i := 0 to ServerSocket1.Socket.ActiveThreads - 1 do
    begin
      ServerSocket1.Socket.Connections[i].SendBuf(Pos,SizeOf(Pos));
    end;
end;

Все работает как надо, но с большими задержками.
Я понимаю, что этот способ совсем неправельный и хотел бы попросить Вас просто пнуть меня в нужном направлении. 
Какие компоненты лучше использовать? Может есть какая-нибудь статья или пример?
Заранее большое спасибо.
PM MAIL   Вверх
jhonyxakep
Дата 9.11.2011, 04:57 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Divide Et Impera
**


Профиль
Группа: Участник
Сообщений: 983
Регистрация: 7.4.2009
Где: Что, Когда?

Репутация: нет
Всего: 8



Как вы принимаете данные у клиента?
PM MAIL ICQ   Вверх
kami
Дата 9.11.2011, 07:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1806
Регистрация: 25.8.2007
Где: Санкт-Петербург

Репутация: 6
Всего: 72



Цитата(Toland2 @  8.11.2011,  21:24 Найти цитируемый пост)
но с большими задержками

Насколько большими?
По идее, должно быть не более 500мс (клиент => сервер) + 500мс (сервер => клиентЫ), ибо размер структуры всего 12 байт (если это не 64бит компилятор smile ) 
Цитата(Toland2 @  8.11.2011,  21:24 Найти цитируемый пост)
Какие компоненты лучше использовать?

Любые, с которыми комфортно работать. Сами компоненты скорости не добавят и не отберут ее.
Цитата(Toland2 @  8.11.2011,  21:24 Найти цитируемый пост)
Я понимаю, что этот способ совсем неправельный

Каждый способ имеет право на существование smile

Цитата(Toland2 @  8.11.2011,  21:24 Найти цитируемый пост)
Может есть какая-нибудь статья или пример?

Есть. Wiki - алгоритм Нагла. И недавно здесь на форуме давал код по отключению этого алгоритма.

Цитата(jhonyxakep @  9.11.2011,  04:57 Найти цитируемый пост)
Как вы принимаете данные у клиента?

Присоединяюсь к вопросу.

P.S. Вы уверены, что "тормоза" идут именно из-за сетевого обмена? 

PM MAIL WWW   Вверх
Toland2
Дата 9.11.2011, 11:49 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 22
Регистрация: 11.10.2011

Репутация: нет
Всего: нет



Принимаю данные через таймер. Не знаю правильно это или нет, но другого способа я не знаю. Вот часть кода таймера:
Код

procedure TForm1.Timer3Timer(Sender: TObject);
var
SizeBuf:integer;
begin
Timer3.Enabled:=false;
SizeBuf:=ClientSocket1.Socket.ReceiveLength;
if SizeBuf <> 0 then
  begin
      //Принимаем позицию вражеских танков
    ClientSocket1.socket.ReceiveBuf(PlayerPosition, SizeOf(PlayerPosition));
    if PlayerPosition.id <> TanksID then
      begin //Если передвинулся вражеский танк, а не наш...
       Tank[PlayerPosition.id].Top:=PlayerPosition.PosY;
       Tank[PlayerPosition.id].Left:=PlayerPosition.PosX;
      end;
   end;
 Timer3.Enabled:=true;
end;


Цитата(kami @  9.11.2011,  07:42 Найти цитируемый пост)
Насколько большими?

Если двигается только один танк, то задержки почти не ощущаются, но когда начинают двигаться 2 и более танка, то они становятся все больше и больше

Цитата(kami @  9.11.2011,  07:42 Найти цитируемый пост)
Есть. Wiki - алгоритм Нагла.И недавно здесь на форуме давал код по отключению этого алгоритма.

Вы мне его и давалиsmile Раньше у меня даже на сервер данные передавались с большими задержками, а после того как я его отключил, задерки стали появляться только при рассылки всем клиентам. Я даже устроил проверку: Переделал программы так, что на клиентах ничего не отображается (пустая форма), а танки двигаются только на сервере. Все работало идеально без единой задерки даже когда подключались 5 клиентов с разных компьютеров

Цитата(kami @  9.11.2011,  07:42 Найти цитируемый пост)
P.S. Вы уверены, что "тормоза" идут именно из-за сетевого обмена? 

Я не знаю в чем причина:( Тестировал на разных компьютерах в разных сетях и результат один и тот же.
PM MAIL   Вверх
kami
Дата 9.11.2011, 12:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1806
Регистрация: 25.8.2007
Где: Санкт-Петербург

Репутация: 6
Всего: 72



Цитата(Toland2 @  9.11.2011,  11:49 Найти цитируемый пост)
задерки стали появляться только при рассылки всем клиентам.

Так переделайте и код сервера под отключение Нагла. Для D7 это (уже переделанное) выглядит так:
Код

procedure TServerWinSocket.Accept(Socket: TSocket);
var
  ClientSocket: TServerClientWinSocket;
  ClientWinSocket: TSocket;
  Addr: TSockAddrIn;
  Len: Integer;
  OldOpenType, NewOpenType: Integer;
  b:Bool; // это добавлено.
begin
  Len := SizeOf(OldOpenType);
  if getsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, PChar(@OldOpenType),
    Len) = 0 then
    try
      if FServerType = stThreadBlocking then
        begin
          NewOpenType := SO_SYNCHRONOUS_NONALERT;
          setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, PChar(@NewOpenType), Len);
        end;
      Len := SizeOf(Addr);
      ClientWinSocket := WinSock.accept(Socket, @Addr, @Len);
      //if not FNeedNagle then
      //  begin
          b:=True;
          SetSockOpt(ClientWinSocket, IPPROTO_TCP, TCP_NODELAY, @b, SizeOf(b)); // а вот и отключение.
       // end;
      if ClientWinSocket <> INVALID_SOCKET then
        begin
          ClientSocket := GetClientSocket(ClientWinSocket);
          if Assigned(FOnSocketEvent) then
            FOnSocketEvent(Self, ClientSocket, seAccept);
          if FServerType = stThreadBlocking then
            begin
              ClientSocket.ASyncStyles := [];
              GetServerThread(ClientSocket);
            end;
        end;
    finally
      Len := SizeOf(OldOpenType);
      setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, PChar(@OldOpenType), Len);
    end;
end;

Это первое.
Второе - принимать из сети что-то по таймеру, мягко говоря, некорректно. 

Попробуйте установить и воспользоваться (ну и разобраться, что да как - код неплохо комментирован) вот этими компонентами (во вложении) - они как нельзя лучше вкупе с отключением набившего оскомину алгоритма подойдут к Вашей задаче. В особенности - методы сервера "отправить всем". В комплекте - небольшой пример. Самое главное изменение, которое нужно будет сделать - это прямо в событии приема (на сервере) передать всем тот же  Stream. Таким образом Вы обезопасите себя от множества проблем, в том числе - и от работы с потоками (они в представленных компонентах не задействуются, таким образом можно безбоязненно обращаться откуда угодно к форме и визуальным компонентам).

Присоединённый файл ( Кол-во скачиваний: 4 )
Присоединённый файл  SimpleTCPTransfer1.zip 10,97 Kb
PM MAIL WWW   Вверх
Toland2
Дата 9.11.2011, 13:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 22
Регистрация: 11.10.2011

Репутация: нет
Всего: нет



kami, спасбо большое! Уже в который раз выручаете! Буду разбираться.
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Delphi: Сети"
Snowy
Poseidon
MetalFan

Запрещено:

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делится вскрытыми компонентами

  • Литературу по Дельфи обсуждаем здесь
  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь
  • 90% ответов на свои вопросы можно найти в DRKB (Delphi Russian Knowledge Base) - крупнейшем в рунете сборнике материалов по Дельфи

Если Вам помогли и атмосфера форума Вам понравилась, то заходите к нам чаще! С уважением, Snowy, Poseidon, MetalFan.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Delphi: Сети | Следующая тема »


 




[ Время генерации скрипта: 0.2056 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.