-
В случае, если запрос GET или POST, то просто читаю из заголовка хост, порт и документ и отсылаю этот заголовок удаленному серверу - это для HTTP. В случае с HTTPS (ssl) ко мне приходит запрос CONNECT и я в таком случае цепляюсь к нужному хосту и порту (443 обычно) и просто делаю непосредственную связь между двумя сокетами.
-
У меня ограничение трафика на слипах работает...
type
TShaper=record
Speed:DWORD;
TotalCount,Count,Time:DWORD;
end;
procedure TPortMapClientThread.DoTunneling(Peer1,Peer2:TCustomWinSocket);
procedure ShapeIt(var Shaper:TShaper;Count: Integer);
var OverTime:integer;
begin
if Shaper.TotalCount=0 then
begin
Shaper.TotalCount:=Count;
Shaper.Count:=Count;
Shaper.Time:=GetTickCount;
exit;
end;
Inc(Shaper.TotalCount,Count);
Inc(Shaper.Count,Count);
if Shaper.Count>Shaper.Speed then
begin
OverTime:=Round(Shaper.Count/Shaper.Speed*1000-(GetTickCount-Shaper.Time));
if OverTime>0 then
begin
Sleep(OverTime);
Shaper.Count:=0;
Shaper.Time:=GetTickCount;
end;
end;
end;
function SendBufFully(Peer:TCustomWinSocket;var Buf; Count: Integer):boolean;
var pBuf:PByte;
s:integer;
begin
result:=false;
pBuf:=@Buf;
while count>0 do
begin
s:=Peer.SendBuf(pBuf^,Count);
if s=0 then exit;
inc(pBuf,s);
dec(Count,s);
end;
result:=true;
end;
var
FDSet: TFDSet;
TimeVal: TTimeVal;
Buf:array[byte] of char;
InShaper,OutShaper:TShaper;
Buf:array[0..4095] of char;
r:integer;
begin
InShaper.TotalCount:=0;
InShaper.Speed:=2048;
OutShaper.TotalCount:=0;
OutShaper.Speed:=2048;
TimeVal.tv_sec := FPortMap.ClientTimeout div 1000;
TimeVal.tv_usec := (FPortMap.ClientTimeout mod 1000) * 1000;
while Peer1.Connected and Peer2.Connected do
begin
FD_ZERO(FDSet);
FD_SET(Peer1.SocketHandle, FDSet);
FD_SET(Peer2.SocketHandle, FDSet);
if select(0, @FDSet, nil, nil, @TimeVal)>0 then
begin
if FD_ISSET(Peer1.SocketHandle, FDSet) then
begin
r:=Peer1.ReceiveBuf(Buf,Length(Buf));
if r=0 then exit;
if not SendBufFully(Peer2,Buf,r) then exit;
ShapeIt(InShaper,r);
end;
if FD_ISSET(Peer2.SocketHandle, FDSet) then
begin
r:=Peer2.ReceiveBuf(Buf,Length(Buf));
if r=0 then exit;
if not SendBufFully(Peer1,Buf,r) then exit;
ShapeIt(OutShaper,r);
end;
end else
exit;
end;
end;
procedure TPortMapClientThread.ClientExecute;
begin
try
RemoteSocket.Open('',FPortMap.RemoteHost,'',FPortMap.RemotePort);
DoTunneling(ClientSocket,RemoteSocket);
finally
RemoteSocket.Close;
ClientSocket.Close;
end;
end;
-
Всем снова привет! Уже больше года этой проблеме и до сих пор не могу решить ее. Проект был отложен и вчера снова взялся за него.
Запустил Wireshark, смотрю пакеты и в момент обрыва наблюдаю, что удаленный сервер (откуда я качаю файл) в одном из последних пакетов TCP выставляет флаги Fin, Push и ACK. Т.е., как я понимаю, он разрывает связь и, видимо, просит меня что-то "протолкнуть" -) (Push). Только вот понять я не могу, почему он это делает...
-
Slym, спасибо за код. Переделал свой код на тот же самый, что и Ваш, единственное отличие - один сокет TClientWinSocket, второй - TServerClientWinSocket. Но проблема полностью осталась :(
-
Может быть есть какой-то баг в D2006? И еще, каким-либо боком это не может быть связано с методом Nagle (либо его отсутствием)?
-
kernel © (27.03.11 14:43) [23] Переделал свой код на тот же самый, что и Ваш, единственное отличие - один сокет TClientWinSocket, второй - TServerClientWinSocketэто зачем? все было вполне универсально т.к.: TServerClientWinSocket = class(TCustomWinSocket)
TClientWinSocket = class(TCustomWinSocket) учи матчасть!
-
kernel © (27.03.11 14:43) [23] Переделал свой код на тот же самый Автоваз в свое время тоже фиат переделывал... показывай, может у тебя ручник к педале газа приделан :) передельщик
-
Ну так это потому что у меня весь сервер на TServerSocket построен и где-то внутри из него вытекает TServerClientWinSocket (т.е. предопределенно вытекает из TServerSocket). А внутри потока уже TClientSocket используется (ThreadConnection). А вот собственно тот проблемный кусок кода. Общение происходит в одну сторону, т.к. в этом месте уже идет принятие чего-либо после GET\POST запроса. Хотя и двухстороннюю передачу тоже делал, ничего не прибавилось и не убавилось :) InShaper.TotalCount:=0;
InShaper.Speed:=2048;
OutShaper.TotalCount:=0;
OutShaper.Speed:=2048;
TimeVal.tv_sec := SocketsTimeout div 1000;
TimeVal.tv_usec := (SocketsTimeout mod 1000) * 1000;
while ClientSocket.Connected and ThreadConnection.Socket.Connected do begin
FD_ZERO(FDSet);
FD_SET(ClientSocket.SocketHandle, FDSet);
FD_SET(ThreadConnection.Socket.SocketHandle, FDSet);
if select(0, @FDSet, nil, nil, @TimeVal) > 0 then begin
if FD_ISSET(ThreadConnection.Socket.SocketHandle, FDSet) then begin
RecLen := ThreadConnection.Socket.ReceiveBuf(SockBuffer, Length(SockBuffer));
if RecLen = 0 then Break;
if not WriteBufferToSocket(ClientSocket, SockBuffer, RecLen) then Break;
ShapeIt(InShaper, RecLen);
end;
end else Break;
end;
ThreadConnection.Close;
ThreadConnection.Free;
-
kernel © (27.03.11 21:54) [27] Ну так это потому что у меня весь сервер на TServerSocket построен и где-то внутри из него вытекает TServerClientWinSocket (т.е. предопределенно вытекает из TServerSocket). А внутри потока уже TClientSocket используется (ThreadConnection). аналогично... TServerSocket и TClientSocket - это "компонентная" обертка над ними внутри юзается WinSocket
kernel © (27.03.11 21:54) [27] есть подозрение что сервак тебе шлет Bad request или иную ошибку возвращает и рвет соединение... проверяй снифером что отсылаешь серверу и что возвращается в первых пакетах от него
-
Неа, никакого Bad request не наблюдается. Я передал заголовок на удаленный сервер и далее все, что к прокси приходит отдаю сразу клиенту. Файл принимается до каких-то пор, затем связь обрывается "на пустом месте" - самому прокси ничего не приходит, однако на более низком уровне наблюдаются всякие TCP ZeroWindow, TCP Windows Update.. FIN PUSH и т.п. ...
В общем, не знаю уже с ним что делать. Думаю полностью сменить подход к написанию этого прокси (хотя вроде все максимум аккуратно делал) и "с нуля" все начинать делать и уже, наверное, не на Delphi :( А то уже больше года прошло и с места проект не сдвинулся...
-
скомпилься на 7 дельфе, если глюк повторяется тогда я низнаю в чем проблема
-
- просто удаленный хост ненавязчиво вам намекает, что у вас слишком медленный канал, вы слишком долго занимаете его пул подключений(далеко не резиновый), и ваш приоритет сравнялся с плинтусом - переходите на режим докачки по частям, либо целиком кэшируйте файл(ы)...
И версия Delphi никакого отношения к этому не имеет.
-
Спасибо большое всем еще раз! Тоже склоняюсь к тому, что написАл han_malign. Только вот вопрос, как теперь ограничивать пропускную способность. Не редко бывает, что сервер не разрешает докачку файла и окно, как я понимаю, будет расти до каких-то пор, пока не разорвется соединение.
> han_malign, > либо целиком кэшируйте файл(ы)
Что именно имеется ввиду?
-
> > > han_malign, > > либо целиком кэшируйте файл(ы) > > Что именно имеется ввиду? > >
быстро скачать и медленно отдавать
-
Ок, все понял. Спасибо. А в случае, если потребуется ограничивать пропускную способность ради того, чтобы канал интернета не занимать, как в этой ситуации поступить можно?
-
...точнее, чтобы не загружать канал интернета
|