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

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

не доходит значение типа integer [D7, WinXP]


Страницы:   1 2

Dmitry_177 ©   (2007-04-28 22:14:00) 

Использую WinSock, протокол TCP, может ли быть такое что не доходит значение типа integer? Просто так то у меня все работает, но иногда, очень редко бывает что недоходит значение типа integer, причем как-то странно то что именно в одном месте..


Dmitry_177   (2007-05-03 10:05:00) [1]

Попробовал вот так:

function KLRecv(s: TSocket; var Buf; len, flags: Integer): Integer;
var
 PBuf: Pointer;   // чтобы двигать ЭТОТ указатель
 BytesNeed: Integer;
 BytesRecv: Integer;
 FDSet: TFDSet;
 TimeOut: TimeVal;
begin
 FD_ZERO(FDSet);
 FD_SET(s, FDSet);
 TimeOut.tv_sec := 60;
 TimeOut.tv_usec := 0;

 PBuf := @Buf;
 BytesNeed := len;
 while BytesNeed > 0 do
   begin
     if select(0, @FDSet, nil, nil, @TimeOut) > 0 then   // чтобы не застопорился на recv
       begin
         BytesRecv := recv(s, PBuf^, BytesNeed, flags);
         if BytesRecv > 0 then
           begin
             Dec(BytesNeed, BytesRecv);
             Inc(DWORD(PBuf), BytesRecv);
           end
         else
           begin
             Result := SOCKET_ERROR;  // это чтобы в самой программе не сверять размер полученных байтов, т.к. всеравно они не все пришли, мне проще сделать это как ошибка SOCKET_ERROR, хоть даже сколько то и было полученно байт..
             Break;
             Exit;
           end;
       end
     else
       begin
         Result := SOCKET_ERROR;   // тоже самое
         Break;
         Exit;
       end;
   end;
Result := len;
end;

и в самой программе:

if KLRecv(KLSock, iRecv, SizeOf(iRecv), 0) <> SOCKET_ERROR then
...

всеравно если посылаю 1 приходит 5, как я понимаю к значению прибавляется размер получаемых данных, т.к. integer 4 байта занимает вот они и прибавляются.. подскажите пожалуйста..


Dmitry_177   (2007-05-03 00:20:00) [2]

как я понял всегда прибавляется на 4.. Наверно это из-за этого: Inc(DWORD(Buf), BytesRead);но эта же строка тоже нужна для того чтобы не в начало буфера записывались последующие вызовы recv.. Что можно с этим сделать?


Dmitry_177   (2007-05-03 00:06:00) [3]

Потом чисто ради эксперимента послал "111", получил "115"


Dmitry_177   (2007-05-03 00:02:00) [4]

Странно как-то.. Используя тот код который я привел выше, посылаю значение типа integer равное "1", получаю "5"


DVM   (2007-05-02 18:07:00) [5]


> Dmitry_177   (02.05.07 17:49) [30]

я вот так делаю:

function THTTPInputThread.ReadData(ABuffer: TBuffer; BytesExpected: integer): integer;
const
 MaxLen = 262144;
var
 TotalBytesToRead, Found, TotalBytesRead, BytesToRead, BytesRead: integer;
 Rfds: TFDSet;
 TempBuff: array [0..Pred(MaxLen)] of Char;
begin
 FD_ZERO(Rfds);
 FD_SET(Sock, Rfds);
 Found := select(Sock, @Rfds, nil, nil, @FTimeout);
 if Found = 0 then
   begin
     // Select timed out
     Result := -1;
     exit;
   end
 else
   if Found = SOCKET_ERROR then
     begin
       // Select error
       Result := -1;
       exit;
     end;
 TotalBytesToRead := 0;
 if BytesExpected <> 0 then
   begin
     TotalBytesToRead := BytesExpected;
   end
 else
   begin
     if ioctlsocket(Sock, FIONREAD, TotalBytesToRead) = SOCKET_ERROR then
       begin
         // Cannot ioctl()
         Result := -1;
         exit;
       end;
     if TotalBytesToRead = 0  then
       begin
         SocketDisconnect();
         Result := 0;
         exit;
       end;
   end;
 TotalBytesRead := 0;
 repeat
   if TotalBytesToRead > MaxLen then
     BytesToRead := MaxLen
   else
     BytesToRead := TotalBytesToRead;
   ZeroMemory(@TempBuff[0], MaxLen);
   BytesRead := recv(Sock, TempBuff, BytesToRead, 0);
   if BytesRead = SOCKET_ERROR then
     begin
       // Read error
       SocketDisconnect();
       Result := -1;
       exit;
     end
   else
     if BytesRead = 0 then
       begin
         SocketDisconnect();
         Result := 0;
         exit;
       end
     else
       begin
         if ABuffer.Size >= 2097152 then
           begin
             SocketDisconnect();
             Result := -1;
             exit;
           end;
         ABuffer.Append(@TempBuff[0], BytesRead);
         TotalBytesRead := TotalBytesRead + BytesRead;
         TotalBytesToRead := TotalBytesToRead - BytesRead;
       end;
 until TotalBytesToRead <= 0;
 Result := TotalBytesRead;
end;


Dmitry_177   (2007-05-02 17:49:00) [6]

Чтобы каждый раз не мучаться при каждой посылке или приеме информации, я думаю лучше написать функции с этим циклом и уже их использовать.. Вот например с recv:

function NewRecv(s: TSocket; var Buf; len, flags: Integer): Integer;
var
 BytesNeed: Integer;
 BytresWrite: Integer;
begin
 BytesNeed := len;
 while BytesNeed > 0 do
   begin
     BytesRead := recv(s, Buf, BytesNeed, flags);
     if BytesRead = SOCKET_ERROR then
       begin
         Result := SOCKET_ERROR;
         Break;
         Exit;
       end;
     if BytesRead = 0 then
       begin
         Result := len - BytesNeed;
         Break;
         Exit;
       end;
     if BytesRead > 0 then
       begin
         Dec(BytesNeed, BytesRead);
         Inc(DWORD(Buf), BytesRead);
       end;
   end;
 Result := len;
end;

Правильно ли так будет?


Сергей М.   (2007-05-02 17:25:00) [7]


> или надо по кускам?


Об этом тебе скажет результат вызова send(), точно так же как результат вызова recv() говорит тебе о том, все ли из запрошенного тобой к чтению фактически прочитано.


Dmitry_177   (2007-05-02 17:21:00) [8]

а как посылать лучше структуру TSelectDataPacket?

send(KLSock, SelectDataPacket, SizeOf(SelectDataPacket), 0)  или надо по кускам?


Сергей М.   (2007-05-02 16:56:00) [9]

var
 buf: Pointer;
 BytesNeed: Integer;
 BytresRead: Integer;
 MyData: TMyType; //TMyType м.б. и Integer, и TSelectDataPacket, и что угодно
..

buf := @MyData;
BytesNeed := SizeOf(MyData);
while BytesNeed > 0 do begin
 BytesRead := recv(KLSock, buf^, Min(BytesNeed, SizeOf(buf));
 if BytesRead >= 0 then begin
   Dec(BytesNeed, BytesRead);
   Inc(DWord(buf), BytesRead);
 end else
  ..
end;


Dmitry_177   (2007-05-02 16:53:00) [10]

я вот так придумал:

var
 b: bool;
 i: integer;
 iRecv: integer;
 RecvSize: integer;
 Buffer: array of Byte;
begin
 b := false;
 i := 0;
 SetLength(Buffer, SizeOf(iRecv));
 while not b do
   begin
     RecvSize := recv(KLSock, Buffer[i], SizeOf(Buffer), 0);
     if RecvSize = Socket_Error then
       begin
         Break;
         Exit;
       end;
     if RecvSize <> SizeOf(Buffer) then
       begin
         Move(Buffer[i], iRecv, RecvSize);
         i := i + RecvSize;
       end
     else
       b := true;
   end;
end;

Правильно ли так будет или можно как-то проще и лучше?


Dmitry_177   (2007-05-02 16:37:00) [11]

мне не очень понятно вот что: вот был вызван recv(KLSock, Buffer, SizeOf(Buffer), 0), вернул он например 2, т.е. было получено 2 байта, как мне потом при вызове следующего recv записать в конец данных в буфере а не в начало, т.е. не на те которые уже были приняты? Вот так: recv(KLSock, Buffer[3], SizeOf(Buffer)-2, 0)?  и как мне реализовать лучше этот цикл? и еще при следующих вызовах recv сколько задавать на получение байт(3 параметр)? так как я уже привел: SizeOf(Buffer)-2?


Сергей М.   (2007-05-02 16:33:00) [12]


> Dmitry_177   (02.05.07 16:16) [22]


Ну пусть даже так.

А теперь представь, что буфер Buffer заполняется полученными в рез-те вызовов ф-ции recv данными - первый полученный байт помещается в Buffer[0], второй - в Buffer[1], третий - в Buffer[2], N-ный - в Buffer[N-1] ..


SpellCaster   (2007-05-02 16:30:00) [13]

Можно и так

var
i: integer
Buffer: array [1..sizeof(integer)] of Byte absolute i;


Dmitry_177   (2007-05-02 16:16:00) [14]

Так?

var
i: integer
Buffer: array of Byte;

SetLength(Buffer, SizeOf(i));
Move(Buffer, i, SizeOf(i));


Сергей М.   (2007-05-02 16:04:00) [15]


> Dmitry_177   (02.05.07 15:53) [19]


Забудь на время про recv.

Простейший тест на знания Паскаля:

Если у тебя есть, к примеру, есть 4 байта, то как получить из них Integer, если имеющиеся байты следуют в Intel-порядке - от младшего к старшему ?


Dmitry_177   (2007-05-02 16:03:00) [16]

на сколько я понимаю, нужно считывать в какой-то буфер, а как его объявлять? и как потом из него считать тот же integer?


Dmitry_177   (2007-05-02 15:53:00) [17]

а как тогда все это склеить? к примеру integer был принят двумя recv-ами, как его склеить в одно?


Сергей М.   (2007-05-02 15:42:00) [18]


> вызывать заново recv?


Да.


> как тогда мне получить значение типа


Вызывать recv до тех пор, пока не будут получены все данные требуемого размера.


> из этих двух recv-ов


Почему двух ?

Если ты ожидаешь, скажем , SizeOf(Integer)=4 байта, то теоретически может потребоваться от одного до четырех вызовов recv.


DVM   (2007-05-02 15:36:00) [19]

recv не знает ничего о TSelectDatapacket - она байты принимает


DVM   (2007-05-02 15:35:00) [20]


> а что тогда делать? вызывать заново recv?

во первых она говорит сколько байт реально прочитано, а во вторых в цикле вызывай пока не получишь все.


Страницы:   1 2

Наверх

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