Конференция "Сети" » Обрыв передачи данных
 
  • kernel © (06.12.10 13:56) [20]
    В случае, если запрос GET или POST, то просто читаю из заголовка хост, порт и документ и отсылаю этот заголовок удаленному серверу - это для HTTP. В случае с HTTPS (ssl) ко мне приходит запрос CONNECT и я в таком случае цепляюсь к нужному хосту и порту (443 обычно) и просто делаю непосредственную связь между двумя сокетами.
  • Slym © (07.12.10 09:22) [21]
    У меня ограничение трафика на слипах работает...
    {$DEFINE Shaper}
    {$IFDEF Shaper}
    type
     TShaper=record
       Speed:DWORD;
       TotalCount,Count,Time:DWORD;
     end;
    {$ENDIF}

    procedure TPortMapClientThread.DoTunneling(Peer1,Peer2:TCustomWinSocket);
    {$IFDEF Shaper}
     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;
    {$ENDIF}

     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;
    {$IFDEF Shaper}
     Buf:array[byte] of char;
     InShaper,OutShaper:TShaper;
    {$ELSE}
     Buf:array[0..4095] of char;
    {$ENDIF}
     r:integer;
    begin
     {$IFDEF Shaper}
       InShaper.TotalCount:=0;
       InShaper.Speed:=2048;
       OutShaper.TotalCount:=0;
       OutShaper.Speed:=2048;
     {$ENDIF}
     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;
           {$IFDEF Shaper}
           ShapeIt(InShaper,r);
           {$ENDIF}
         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;
           {$IFDEF Shaper}
           ShapeIt(OutShaper,r);
           {$ENDIF}
         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;

  • kernel © (27.03.11 14:39) [22]
    Всем снова привет! Уже больше года этой проблеме и до сих пор не могу решить ее. Проект был отложен и вчера снова взялся за него.

    Запустил Wireshark, смотрю пакеты и в момент обрыва наблюдаю, что удаленный сервер (откуда я качаю файл) в одном из последних пакетов TCP выставляет флаги Fin, Push и ACK. Т.е., как я понимаю, он разрывает связь и, видимо, просит меня что-то "протолкнуть" -) (Push). Только вот понять я не могу, почему он это делает...
  • kernel © (27.03.11 14:43) [23]
    Slym, спасибо за код. Переделал свой код на тот же самый, что и Ваш, единственное отличие - один сокет TClientWinSocket, второй - TServerClientWinSocket. Но проблема полностью осталась :(
  • kernel © (27.03.11 15:33) [24]
    Может быть есть какой-то баг в D2006? И еще, каким-либо боком это не может быть связано с методом Nagle (либо его отсутствием)?
  • Slym © (27.03.11 21:01) [25]
    kernel ©   (27.03.11 14:43) [23]
    Переделал свой код на тот же самый, что и Ваш, единственное отличие - один сокет TClientWinSocket, второй - TServerClientWinSocket

    это зачем? все было вполне универсально т.к.:
    TServerClientWinSocket = class(TCustomWinSocket)
    TClientWinSocket = class(TCustomWinSocket)


    учи матчасть!
  • Slym © (27.03.11 21:07) [26]
    kernel ©   (27.03.11 14:43) [23]
    Переделал свой код на тот же самый

    Автоваз в свое время тоже фиат переделывал... показывай, может у тебя ручник к педале газа приделан :) передельщик
  • kernel © (27.03.11 21:54) [27]
    Ну так это потому что у меня весь сервер на 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;

  • Slym © (28.03.11 06:57) [28]
    kernel ©   (27.03.11 21:54) [27]
    Ну так это потому что у меня весь сервер на TServerSocket построен и где-то внутри из него вытекает TServerClientWinSocket (т.е. предопределенно вытекает из TServerSocket). А внутри потока уже TClientSocket используется (ThreadConnection).

    аналогично... TServerSocket и TClientSocket - это "компонентная" обертка над ними внутри юзается WinSocket

    kernel ©   (27.03.11 21:54) [27]
    есть подозрение что сервак тебе шлет Bad request или иную ошибку возвращает и рвет соединение... проверяй снифером что отсылаешь серверу и что возвращается в первых пакетах от него
  • kernel © (28.03.11 14:57) [29]
    Неа, никакого Bad request не наблюдается. Я передал заголовок на удаленный сервер и далее все, что к прокси приходит отдаю сразу клиенту. Файл принимается до каких-то пор, затем связь обрывается "на пустом месте" - самому прокси ничего не приходит, однако на более низком уровне наблюдаются всякие TCP ZeroWindow, TCP Windows Update.. FIN PUSH и т.п. ...

    В общем, не знаю уже с ним что делать. Думаю полностью сменить подход к написанию этого прокси (хотя вроде все максимум аккуратно делал) и "с нуля" все начинать делать и уже, наверное, не на Delphi :( А то уже больше года прошло и с места проект не сдвинулся...
  • Slym © (29.03.11 12:12) [30]
    скомпилься на 7 дельфе, если глюк повторяется тогда я низнаю в чем проблема
  • han_malign (29.03.11 15:14) [31]
    - просто удаленный хост ненавязчиво вам намекает, что у вас слишком медленный канал, вы слишком долго занимаете его пул подключений(далеко не резиновый), и ваш приоритет сравнялся с плинтусом - переходите на режим докачки по частям, либо целиком кэшируйте файл(ы)...

    И версия Delphi никакого отношения к этому не имеет.
  • kernel © (02.04.11 09:20) [32]
    Спасибо большое всем еще раз!
    Тоже склоняюсь к тому, что написАл han_malign. Только вот вопрос, как теперь ограничивать пропускную способность. Не редко бывает, что сервер не разрешает докачку файла и окно, как я понимаю, будет расти до каких-то пор, пока не разорвется соединение.


    > han_malign,
    > либо целиком кэшируйте файл(ы)

    Что именно имеется ввиду?
  • Slym © (02.04.11 09:53) [33]

    >
    > > han_malign,
    > > либо целиком кэшируйте файл(ы)
    >
    > Что именно имеется ввиду?
    >
    >

    быстро скачать и медленно отдавать
  • kernel © (02.04.11 10:21) [34]
    Ок, все понял. Спасибо.
    А в случае, если потребуется ограничивать пропускную способность ради того, чтобы канал интернета не занимать, как в этой ситуации поступить можно?
  • kernel © (02.04.11 10:21) [35]
    ...точнее, чтобы не загружать канал интернета
 
Конференция "Сети" » Обрыв передачи данных
Есть новые Нет новых   [134437   +27][b:0][p:0.004]