![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
TServerSocket/TClientSocket SendText [D7]
Андрей © (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]
Думаю что у тебя ошибка в программе.