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

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Многопоточный сервак 
:(
    Опции темы
Antony41
Дата 18.2.2013, 16:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



кстати мне sleep(10) очень помогло впринципе засыпание на 10 мс незаметно, это ни как не влияет на приём данных... а вот в цикле с GetticCount самое оно. Загрузка ЦП при 20 подключ. клиентов составила 0-1% при опросе клиентов каждые 3 сек. Провёл тестирование подключил 20 клиентов, и они стабильно обменивались данными с сервером 7-8 часов при закрытии серва все 20 клиентов были на связи. Пока ошибок не выявил.

Это сообщение отредактировал(а) Antony41 - 18.2.2013, 16:39
PM MAIL   Вверх
Antony41
Дата 9.4.2013, 22:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



Короче тут такая ситуация вышла... Я запарился с этими vcl (TClientSocket) и решил с чистого листа на Socket API впринципе пока все прекрасно...
Вопросик образовался:
Я Выполняю прием данных в основном потоке тоесть
Код

I := recv(vSocket, Buff, iStillToReceive, 0);
 
пока выполняется эта функция, блокируется главный поток на время приёма данных. (ну я имею ввиду зависание интерфейса).
никакие тут ProcessMessages не помогают,
Что будет если я работу и прием данных напишу в отдельном потоке? ни каких конфликтов не возникнет при переключении потоков системой?
или что посоветуете.
PM MAIL   Вверх
Чучмек
Дата 10.4.2013, 09:10 (ссылка)  | (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


НЭТ БИЛЭТ
**


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

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



Цитата(Antony41 @  9.4.2013,  22:25 Найти цитируемый пост)
пока выполняется эта функция, блокируется главный поток на время приёма данных. (ну я имею ввиду зависание интерфейса).
никакие тут ProcessMessages не помогают,

Antony41, есть неблокирующий режим, есть select.


--------------------
умную мысль держи при себе, а дурной - поделись с другими 
PM MAIL   Вверх
Antony41
Дата 10.4.2013, 17:59 (ссылка)  | (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



ок спс... щас поюзаем

Добавлено через 10 минут и 26 секунд
блин... чето я запутался немного.
неблокирующий сокет создает отдельный поток на каждое подключение, так не будет ди тоже самое что я буду использовать блокирующий сокет в отдельном потоке, просто создам поток и суну туда все функции работы с сокетом.?
PM MAIL   Вверх
Antony41
Дата 10.4.2013, 20:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



Ребят помогите чёто не пойму как надо. Вот процедура приема данных у клиента
проблема в том что иногда структура не верно заполняется, а иногда верно.
Если проверять когда данные от сервера ушли уже точно, то пакет приходит нормально, а вот если не ушли или ушли не полностью то иногда пакет поступает в обработку (processing()) и обрабатывается не верно.

Короче серв шлет тестовый пакет каждые 5 сек, если я буду проверять пришел пакет или нет каждые 5 сек, то ошибки обработки (тут не понятно данные вроде по размеру заполнятся полностью, может там какие нибудь спец симполы в начале или конце пакета добавляются?)  
А если я буду делать проверку ReceiveNBytes каждые напр. 6-7 сек то всё ОК. smile 

Код

function TCSocketThread.ReceiveNBytes: Integer;
var
  SelectResult, I, iStillToReceive, iStillToReceive2: Integer;
  Timeout: timeval;
  fds: TFDSet;
  TempData: TData;
  Buff: array [0..10000] of Byte;
  SIZE_OF_STRUCT: Integer;
  MS: TMemoryStream;
begin
  SelectResult := 0;
  I := 0;
  FD_ZERO(fds);
  FD_SET(vSocket, fds);
  Timeout.tv_sec := 0;
  Timeout.tv_usec := 500000; //Устанавливаем таймаут – 0,5сек.
  SIZE_OF_STRUCT := SizeOf(TempData);
  iStillToReceive := SIZE_OF_STRUCT; //от сюда будут отниматься принятые байты
  iStillToReceive2 := 0; //сюда будут суммироваться кол-во принятых байт
  repeat
      //Ждем прихода данных
      SelectResult := select(0, @fds, nil, nil, @Timeout);
      //Выход по таймауту
      if SelectResult = SOCKET_ERROR then
        begin
          Result := -1;
          Break;
        end
      else
        if SelectResult = 0 then //TimeOut
          begin
            Result := -1;
            Break;
          end
        else
          if SelectResult < 0 then //Произошла какая-то ошибка при исполнении select()
            begin
              //Result := WSAGetLastError;
              Result := -1;
              Break;
            end;
            //Прием нескольких байт
            I := recv(vSocket, Buff, iStillToReceive, 0);

            if I = 0 then //Произошла ошибка при вызове функции recv() или сокет был закрыт
            begin
              //Result := WSAGetLastError
              Result := -1;
              Break;
            end
            else
              if I = SOCKET_ERROR then
                begin
                  Result := -1;
                  Break;
                end
              else
                begin
                  //Изменяем величину счетчика и буфер
                  iStillToReceive := iStillToReceive - I;
                  iStillToReceive2 := iStillToReceive2 + I;
                end;
  until iStillToReceive = 0;

  if Result = -1 then
    Exit
  else
    begin
      MS := TMemoryStream.Create;
      MS.Write(Buff, SIZE_OF_STRUCT);
      MS.Seek(0, soFromBeginning); //Устанавливаем начальную позицию
      MS.Read(TempData, MS.Size); //Читаем данные в нашу структуру
      if MS.Size = iStillToReceive2 then
        Processing(@TempData);
      MS.Free;
      Result := 0;
    end;
end;

PM MAIL   Вверх
Чучмек
Дата 11.4.2013, 00:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


НЭТ БИЛЭТ
**


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

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



Цитата(Antony41 @  10.4.2013,  17:59 Найти цитируемый пост)
неблокирующий сокет создает отдельный поток на каждое подключение, 

Antony41, не выдумывай.
Код

...
const WinSockMsg=WM_USER+100;

type
  TForm1 = class(TForm)
    Memo1: TMemo;
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
    procedure WinSockMSGProc(var msg:TMessage); message WinSockMsg;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}
var
  wd:WSAData;

const
  port:word=80;
  host='forum.vingrad.ru';
  pg='forum/topic-362367/view-all.html';

procedure TForm1.Button1Click(Sender: TObject);
var
  s:TSocket;
  sa:TSockAddrIn;
  ip:Cardinal;
  pi:PHostEnt;
  str:ansistring;
begin
  s:=socket(AF_INET,SOCK_STREAM,IPPROTO_IP);
  pi:=gethostbyname(host);
  ip:= pbyte(pi.h_addr_list^+3)^ or
      (pbyte(pi.h_addr_list^+2)^ shl 8)  or
      (pbyte(pi.h_addr_list^+1)^ shl 16) or
      (pbyte(pi.h_addr_list^)^   shl 24);
  FillChar(sa,sizeof(sa),0);
  sa.sin_family:=PF_INET;
  sa.sin_port:=htons(port);
  sa.sin_addr.S_addr:=htonl(ip);
  connect(s,TSockAddr(sa),sizeof(sa));
  str:='GET /'+pg+' HTTP/1.1'#13#10+
       'Connection: close'#13#10+
       'Host: '+host+#13#10+
       #13#10;
  send(s,str[1],length(str),0);
  WSAAsyncSelect(s,Form1.Handle,Cardinal(WinSockMsg),FD_READ);
end;




procedure TForm1.FormCreate(Sender: TObject);
begin
  WSAStartup(1,wd);
end;

procedure TForm1.WinSockMSGProc(var msg: TMessage);
var
  s:TSocket;
  hEvent,
  error:word;
  rb:integer;
  buff:array[word] of ansichar;
begin
  s:=msg.WParam;
  hEvent:=msg.LParam and $FFFF ;
  error:=msg.LParam shr 16;
  if hEvent=FD_READ then
  begin
    rb:=recv(s,buff,sizeof(buff),0);
    Memo1.Text:=Memo1.Text+UTF8ToString(copy(buff,1,rb));
  end;
end;

end.


Добавлено через 13 минут и 52 секунды
Нажми несколько раз подряд на Button1.
Antony41,неблокирующий режим для того и существует, чтобы обойтись без дополнительных потоков.
Есть как минимум один способ на блокирующем режиме - проверять состояние сокета через  select (посмотри выше, я давал пример где проверялось подключение),
и есть несколько способов на неблокирующих.


--------------------
умную мысль держи при себе, а дурной - поделись с другими 
PM MAIL   Вверх
Antony41
Дата 11.4.2013, 17:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



Просто терпения нет хочется быстрее выучить и написать уже рабочую нормальную прогу...))) Пошел снова читать)))
PM MAIL   Вверх
Antony41
Дата 11.4.2013, 20:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



завтра если будет время перепишу всё под неблокирующий. посмотрим что из этого выйдет.
тут я так понимаю select  timeout для recv задавать не нужно, так как прием данных будет возникать по событию FD_READ и вечного ожидания данных не будет? 
PM MAIL   Вверх
Чучмек
Дата 11.4.2013, 21:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


НЭТ БИЛЭТ
**


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

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



Цитата(Antony41 @  11.4.2013,  20:33 Найти цитируемый пост)
тут я так понимаю select  timeout для recv задавать не нужно, так как прием данных будет возникать по событию FD_READ и вечного ожидания данных не будет? 

Да.
WSAAsyncSelect "привязывает" оконное сообщение к сокету(или, точнее, события сокета к оконному сообщению) и переводит сокет в асинхронный(неблокирующий) режим. Можно привязать одно или несколько событий FD_xxx. 




--------------------
умную мысль держи при себе, а дурной - поделись с другими 
PM MAIL   Вверх
Antony41
Дата 15.4.2013, 10:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



чот то не выходит,  
Чучмек, 
Цитата

Код

procedure TForm1.WinSockMSGProc(var msg: TMessage);
var
  s:TSocket;
  hEvent,
  error:word;
  rb:integer;
  buff:array[word] of ansichar;
begin
  s:=msg.WParam;
  hEvent:=msg.LParam and $FFFF ;
  error:=msg.LParam shr 16;
  if hEvent=FD_READ then
  begin
    rb:=recv(s,buff,sizeof(buff),0);
    Memo1.Text:=Memo1.Text+UTF8ToString(copy(buff,1,rb));
  end;
end;


Почему так то разве если пакет придут по частям то ведь эта функция сработает не корректно, ведь у нас   buff:array[word] of ansichar; определяется каждый раз заново

короче я не пойму я уже всё сделал в одном основном потоке, сделал привязал событие FD_READ к сообщению
всё ок при отправке данных, событие возникает нормально при чём сообщение которое отправляется обрабатывается несколько раз, и приходит нужное число байт, но буфер пустой(((( как правильно принимать рубленные пакеты в асинхронном режиме а именно буфер каких нибудь байт.... блин честное слово запарился, проект пользуется спросом а я не могу тут передачу данных наладить(((Что ж всё так печально то, уже и на стандартные компоненты забил засунулся в API а толку... smile

Добавлено через 4 минуты и 4 секунды
код не могу предоставить на работу нужно вечером помучаюсь еще на так я и не понял... блин Хелпинг...
PM MAIL   Вверх
Чучмек
Дата 15.4.2013, 10:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


НЭТ БИЛЭТ
**


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

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



Цитата(Antony41 @  15.4.2013,  10:22 Найти цитируемый пост)
Почему так то разве если пакет придут по частям то ведь эта функция сработает не корректно, ведь у нас   buff:array[word] of ansichar; определяется каждый раз заново

Ты все правильно понимаешь. Пример на неблокирующий режим и только.
Конечно, буфер для сборки пакета должен быть глобальным. Как глобально Memo1.  
Кроме того, если возможно несколько соединений одновременно - под каждый сокет должен быть свой буфер.



--------------------
умную мысль держи при себе, а дурной - поделись с другими 
PM MAIL   Вверх
Antony41
Дата 15.4.2013, 15:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



блин приходит пустой пакет(((( как правильно принять данные в ассинхронном режиме не блокирующем?
PM MAIL   Вверх
Antony41
Дата 15.4.2013, 16:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



Код

var
  Buff: array [0..500] of char;
  iStillToReceive: integer = 0; 

procedure TMainForm.WinSockMSGProc(var msg: TMessage); //при FD_READ
var
  I: Integer;
  S: TSocket;
begin
  s:=msg.WParam;

          I := recv(S, Buff, 100, 0);
          iStillToReceive := iStillToReceive + I;


  if iStillToReceive = 100 then //Вот тут чё то не так
    begin
          Log.Lines.Add(Buff);
    end;

end;


если поставить например вместо if iStillToReceive = 100 then, iStillToReceive = SizeOf(Buff) или 200 то данных в структуре нет, мало того еще и ошибка, а вот если сто +- то читается нормально и там те данные которые я передал
PM MAIL   Вверх
Antony41
Дата 15.4.2013, 17:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



тоесть не не так, получается если я ставлю размер принимаемого буфера Buff: array [0..500] of Char; то всё пока нормально приходит 
а если поставить уже Buff: array [0..1000] of Char, то уже пустой буфер. как так

Код

procedure TMainForm.WinSockMSGProc(var msg: TMessage); //при FD_READ
var
  I: Integer;
  S: TSocket;
begin
  s:=msg.WParam;
          I := recv(S, Buff, SizeOf(Buff), 0);
          iStillToReceive := iStillToReceive + I;
  if iStillToReceive = SizeOf(Buff) then 
    begin
          Log.Lines.Add(Buff);
    end;
end;

PM MAIL   Вверх
Чучмек
Дата 15.4.2013, 17:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


НЭТ БИЛЭТ
**


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

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




Цитата(Antony41 @  15.4.2013,  17:06 Найти цитируемый пост)
 I := recv(S, Buff, SizeOf(Buff), 0);

Ты ведь пакет собираешь.
Код

 I := recv(S, Buff+iStillToReceive , SizeOf(Buff)-iStillToReceive , 0)

Цитата(Antony41 @  15.4.2013,  16:44 Найти цитируемый пост)
Вот тут чё то не так

Пришел  первый кусок (меньше чем указываешь в recv) -сумма меньше. Пришел второй кусок -сумма уже больше.



--------------------
умную мысль держи при себе, а дурной - поделись с другими 
PM MAIL   Вверх
Страницы: (6) Все « Первая ... 2 3 [4] 5 6 
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Delphi: Сети"
Snowy
Poseidon
MetalFan

Запрещено:

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

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

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

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

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


 




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


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

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