Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

TServerSocket/TClientSocket SendText [D7]


Страницы:   1 2

Андрей ©   (2008-10-29 14:36:00) 

Уважаемые, не подскажете, от чего может зависеть скорость передачи/приема пакетов? При тесте на локальной машине все летает, а как только подключаю в локальную сеть, так начинаются задержки отправки/приема (приложение работает по принципу: клиент отослал на сервер пакет, тот его разослал всем подключившимся, в том числе и тому, кто отослал). На сеть грешить сложно, т.к. обычные чаты в ней работают практически без задержек. Есть различие в скорости на чем делать клиента/сервер синхронный/асинхронный режимы?


Сергей М.   (2008-11-06 21:04:00) [1]


> Тын-Дын ©   (06.11.08 20:35) [25]


А по барабану на какой.

WSA 1.01 работает везде одинаково


Тын-Дын   (2008-11-06 20:35:00) [2]


> Андрей   (29.10.08 14:36)  


А на какой операционной системе проверяешь?


Сергей М.   (2008-11-06 20:28:00) [3]

Логика хоть и неважнецкая, но с этим все в порядке - получил шматок текста, дописал в конец стат.буфера, тут же обработал тек.содержимое буфера с должной его коррекцией (если таковая требуется) после обработки.


Тын-Дын   (2008-11-06 20:21:00) [4]


> Сергей М. ©   (06.11.08 20:11) [22]
>
> > в нём ошибка
>
>
> Нет в нем в этом смысле ошибки.
> Данные не потеряются, так что цикл вовсе не обязателен.


Судя по постам выше, у автора на это может быть логика завязана.


Сергей М.   (2008-11-06 20:11:00) [5]


> в нём ошибка


Нет в нем в этом смысле ошибки.
Данные не потеряются, так что цикл вовсе не обязателен.


Тын-Дын   (2008-11-06 19:45:00) [6]

Сомнения вызывает код чтения пришедших данных.
Более того - в нём ошибка.
Правильный алгоритм такой:

var
 s: String;
begin
 s := '';
 while Socket.ReceiveLength>0 do s := s+Socket.ReceiveText;
...


Андрей   (2008-11-02 21:11:00) [7]

Вот ... :(
3 дня промучался. Сейчас ради эксперимента убрал на сервере
s := Socket.ReceiveText;и вставил его в отображение Memo.
Откликнулся мгновенно. Поставил эту строку назад и все летает.
Что было так и не понял. Наверное, какой-то глюк.
Завтра тестить буду. Спасибо за отклики.


Сергей М.   (2008-11-02 20:58:00) [8]

Не верю.

ReceiveText в контексте этого обработчика должна выполниться практически мгновенно.


Андрей   (2008-11-02 19:25:00) [9]


> Отключать алгоритм Нагеля и на стороне клиента и на стороне
> сервера следует сразу после установки соединения.

Так со стороны клиента, вроде, никаких задержек нет. Сервер начинает обрабатыват событие OnClientRead в ту же секунду, в какую клиент отсылает сообщение. Задержка начинается при попытке прочесть данные с помощью ReceiveText. Как раз между первым и вторым выводом в Memo сообщения.

Memo1.Lines.Add('['+TimeToStr(Time)+'] NO_DELAY установлен и ='+IntToStr(i));
// здесь секунды клиента и сервера совпадают
s := Socket.ReceiveText;
// а здесь уже разница в 4-5с
Memo1.Lines.Add('['+TimeToStr(Time)+']  получил сообщение от клиента: '+s);

Вставил отключение Нагеля на событие ClientSocketConnect результат тот же :(

И еще одна странность: вижу, что после начала выполнения оператора  ReceiveText идет фактическая задержка, однако строки

[14:33:11]  получил сообщение от клиента: #Mпервое сообщение      
[14:33:15] вошли в процедуру #M

вываливаются одновременно в [14:33:15]


> SetSockOpt(Socket,SOL_SOCKET,SO_SNDBUF,@i,len);

это я вставил на всякий случай, т.к. везде (где я нашел описания параметров сокета) сказано, что, если буфер отправки будет = 0, то кэшироваться сообщения не будут, а будут отправляться сразу.


Сергей М.   (2008-11-02 18:10:00) [10]


>  i:=0;
>  SetSockOpt(Socket,SOL_SOCKET,SO_SNDBUF,@i,len);


Это лишнее


Сергей М.   (2008-11-02 18:05:00) [11]

Отключать алгоритм Нагеля и на стороне клиента и на стороне сервера следует сразу после установки соединения.


Андрей   (2008-11-02 14:54:00) [12]


procedure Tfrm1.sServerSocketClientRead(Sender: TObject;
         Socket: TCustomWinSocket);
var
 s, from_, to_, color_, time_, temp_ : string;
 game_   : string[8];
 i,j     : Integer;
begin
 Memo1.Lines.Add('['+TimeToStr(Time)+'] handle='+IntToStr(Socket.SocketHandle));
 j:=sizeof(i);
 GetSockOpt(Socket.SocketHandle,SOL_SOCKET,SO_SNDBUF,@i,j);
 Memo1.Lines.Add('['+TimeToStr(Time)+'] SO_SNDBUF='+IntToStr(i));
 GetSockOpt(Socket.SocketHandle,IPPROTO_TCP,TCP_NODELAY,@i,j);
 Memo1.Lines.Add('['+TimeToStr(Time)+'] NO_DELAY установлен и ='+IntToStr(i));
 s := Socket.ReceiveText;
 Memo1.Lines.Add('['+TimeToStr(Time)+']  получил сообщение от клиента: '+s);

if (Copy(s,1,2) = '#M')then begin
   Memo1.Lines.Add('['+TimeToStr(Time)+'] вошли в процедуру #M');
   for i := 0 to sServerSocket.Socket.ActiveConnections-1 do
     sServerSocket.Socket.Connections[i].SendText(s+cDelitel);
   Delete(s,1,2);
   Memo1.Lines.Add('['+TimeToStr(Time)+']  рассылаю сообщения клиентам '+ Copy(s,1,Pos(';',s)-1)+'> '+Copy( s, Pos(';',s)+1, Length(s)-Pos(';',s) ) );
   Exit;
 end;

end;

procedure Tfrm1.sServerSocketGetSocket(Sender: TObject; Socket: Integer;
 var ClientSocket: TServerClientWinSocket);
var
 i, len : integer;
begin
 len:=sizeof(i);
 i:=0;
 SetSockOpt(Socket,SOL_SOCKET,SO_SNDBUF,@i,len);
 i:=1;
 SetSockOpt(Socket,IPPROTO_TCP,TCP_NODELAY,@i,sizeof(i));
end;


в результате получаю
на сервере:

[14:33:11] handle=272
[14:33:11] SO_SNDBUF=0
[14:33:11] NO_DELAY установлен и =1
здесь идет задержка и потом вываливаются сразу оставшиеся строки
[14:33:11]  получил сообщение от клиента: #Mпервое сообщение      
[14:33:15] вошли в процедуру #M
[14:33:15]  рассылаю сообщения клиентам> первое сообщение

у клиента:

[14:33:11]  посылаю сообщение на сервер: первое сообщение
[14:33:11]  отослал
[14:33:15]  получил сообщение от сервера: #Mпервое сообщение#end#
[14:33:15] сообщение с сервера после оработки>первое сообщение


Т.е. буфер отсылки сокета обнулен, TCP_NODELAY отключена, а задержка на сервере между ReceiveText и отсылкой по клиентам составляет 4с
У меня уже мозги скоро закипят :) помогите, плиз, укажите, где у меня ошибка.


Андрей   (2008-11-02 00:03:00) [13]

Похоже глупость сморозил в предыдущем вопросе :) . Где можно почитать про все параметры setsockopt? Желательно на русском, но можно и на английском, если на русском нет :)


Андрей   (2008-11-01 23:34:00) [14]

Если опция TCP_NODELAY установлена с помощью setsockopt, то она действует в пределах только указанного сокета или это глобальное изменение настроек конкретного компа для работы с сетью?


Андрей   (2008-11-01 23:06:00) [15]

Вставил на сервере и клиенте в обработку приема и отсылки сообщений
вывод на экран TimeToStr(Time):
Задержка происходит на сервере между приемом строки и отправкой ее по клиентам.
Вопрос - почему и как это победить? Если это алгоритм Нагеля, то как его отключить в Делфи?

procedure TfrmMy.sServerSocketClientRead(Sender: TObject;
        Socket: TCustomWinSocket);
var
i     : Integer;
begin
s:=Socket.ReceiveText;
Memo1.Lines.Add('['+TimeToStr(Time)+']  получил сообщение от клиента: '+s);
if Copy(s,1,2) = '#M' then begin  // обработка сервером
  for i := 0 to sServerSocket.Socket.ActiveConnections-1 do
    sServerSocket.Socket.Connections[i].SendText(s+cDelitel);
  Memo1.Lines.Add('['+TimeToStr(Time)+']  рассылаю сообщения клиентам ');
  Exit;
end;
end;


Сергей М.   (2008-11-01 16:59:00) [16]


> Просветите, пожалуйста.


Вот тебе информация к размышлению на досуге :

SendText - это функциональныйметод, он возвращает результат, от значения которого напрямую зависит дальнейшее ветвление правильногоалгоритма.

Ты этот результат игнорируешь, следовательно, в произвольных "боевых" условиях твой алгоритм рано или поздно даст сбой.


Андрей   (2008-11-01 16:13:00) [17]

Почитаю на досуге, попробую разобраться :)
А что за
>  довольно важных доработок/переработок

требует код? Просветите, пожалуйста.


Сергей М.   (2008-11-01 15:41:00) [18]

Явных несуразностей пока не видно, хотя код и требует некоторых довольно важных доработок/переработок.

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

http://www.google.ru/search?hl=ru&newwindow=1&client=firefox-a&rls=org.mozilla%3Aru%3Aofficial&hs=6Gv&q=Nagle+SetSockOpt++TCP_NODELAY&btnG=%D0%9F%D0%BE%D0%B8%D1%81%D0%BA&lr=lang_ru&aq=f&oq=


Андрей   (2008-11-01 14:46:00) [19]

Если не трудно, посмотрите, где может скрываться эта ошибка :)
Вроде все просто и на скорость передачи здесь ничего влиять не должно?

Const
 cDelitel : String = '#end#';


procedure ClientDataProc(Socket:TCustomWinSocket; s:string);
begin
if Copy(s,1,2) = '#M' then begin
 Delete(s,1,2);
 ChatMemo.Lines.Add('['+TimeToStr(Time)+']  '+ Copy(s,1,Pos(';',s)-1)+'> '+
           Copy( s, Pos(';',s)+1, Length(s)-Pos(';',s) ) );
 Exit;
end;
end;

procedure TfrmMy.sClientSocketRead(Sender: TObject; Socket: TCustomWinSocket);
var
 s : string;
 i : integer;
begin
 s:=Socket.ReceiveText; // присваиваем s полученную строку из Socket
 if ClientBuf<>''
   then ClientBuf := ClientBuf+s  // в буфере был кусок какой-то стороки
   else ClientBuf := s;
 i:=0;
 repeat // разделяем строку, если одновременно пришло несколько
   i:=Pos(cDelitel,ClientBuf);   // ищем раздлелитель строк в буфере
   if i<>0 then begin   // найден разделитель строк
     s:=Copy(ClientBuf,1,i-1); // копируем одну пришедшую строку в s
     Delete(ClientBuf,1,i+Length(cDelitel)-1); // удаляем из буфера уже скопированную строку
     ClientDataProc(sClientSocket.Socket,s) // обрабатываем выделенную строку
   end;
 until i=0; // повторять, пока будет не найден разделитель строк
end;

procedure TfrmMy.TextEditKeyDown(Sender: TObject; var Key: Word;
         Shift: TShiftState);
var
 s:  string;
 i:  integer;
begin
 if Key = VK_RETURN then begin  // нажата клавиша Enter
   s := '#M'+NickName+';'+TextEdit.Text; // Добавляем наше имя (от кого) и само сообщение
   If sServerSocket.Active=True then  // проверка, в каком режиме находится программа
     For i:=0 to sServerSocket.Socket.ActiveConnections-1 do  // отправляем сообщение с сервера всем пользователям
       sServerSocket.Socket.Connections[i].SendText(s)
   else  // отправляем сообщение с клиента
     sClientSocket.Socket.SendText(s);
   TextEdit.Clear;  // очищаем TextEdit
 end;
 ActiveControl := TextEdit;
end;

procedure TfrmMy.sServerSocketClientRead(Sender: TObject;
         Socket: TCustomWinSocket);
var
 i     : Integer;
begin
 if Copy(s,1,2) = '#M' then begin  // обработка сервером
   for i := 0 to sServerSocket.Socket.ActiveConnections-1 do
     sServerSocket.Socket.Connections[i].SendText(s+cDelitel);
   Exit;
 end;
end;


Сергей М.   (2008-11-01 08:25:00) [20]


> Андрей   (31.10.08 20:28) [6]


Думаю что у тебя ошибка в программе.


Страницы:   1 2

Наверх

Титульная страница Поиск, карта сайта Написать письмо