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

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

Ошибка AV в потоке [D6]


Страницы:   1 2

DelphiN! ©   (2008-04-07 14:30:00) 

Пытаюсь отправить данные в потоке, однако иногдапри обращении к параметру передаваемому в поток возникает исключение Access Violation. Вот код создания потока и самого потока, отправляющего данные через сокет :


type
 TSendStreamParam = record
   Socket: TCustomWinSocket;
   Stream: TStream;
 end;
var
 SendStreamParam: TSendStreamParam;
 SendStreamCriticalSection: TCriticalSection;

 
function TDATA.SendStream(var Socket: TCustomWinSocket; Stream: TStream): Boolean;
 procedure Send(Par: Pointer);
 var
   i: integer;
   buff: array[0..65536] of byte;
   p: ^TSendStreamParam;
 begin
   try
     SendStreamCriticalSection.Enter;
     try
       p := Par;
       p.Stream.Position:=0; Access violation возникает тут
       repeat
         i:=p.Stream.Read(buff,SizeOf(buff));
         while p.Socket.SendBuf(buff,i)=-1 do
       until i=0;
       p.Stream.Free;
       p.Socket.Close;
       //p.Socket.Free;
     except
       //
     end;
   finally
     SendStreamCriticalSection.Leave;
   end;
 end;
var
 c: Cardinal;
begin
 SendStreamParam.Socket := Socket;
 SendStreamParam.Stream := Stream;
 BeginThread(nil,SizeOf(SendStreamParam),@Send,@SendStreamParam,0,c);
end;


В чем может быть дело?


Сергей М.   (2008-04-08 13:09:00) [1]

Да и вообще - в таких вот условиях соответствующий велосипед уже изобретен: сервер работая в stThreaedBlockung в доп.потоке читает клиентствий запрос, синхронизирует его выполнение и формирование стрима-рез-та с осн.потоком (метод Synchronize), вызывает метод SendStream для возврату клиенту рез-та и преспокойно закрывает соединение.


Сергей М.   (2008-04-08 12:57:00) [2]


> в отдельный поток нужно брать только отсылку данных. Обработка
> запроса и формирование отсылаемой информации должны проходить
> в основном потоке


И эта блажь оправдана только тем, что тебе по каким-то причинам не удалось выполнить и то и другое в доп.потоке ?

Мда ..

Ну что ж, хозяин - барин)

Можно сделать так - доп.поток по окончанию работы посылает любой предопределенное тобой сообщение какому-либо окну осн.потока, указывая при этом параметром идентификатор соединения. По получению сообщения осн.поток закрывает указанное соединение.

Только вот юзеров твоего суперпупер-сервера жалко)


DelphiN!   (2008-04-08 12:40:00) [3]


> Сергей М. ©   (08.04.08 12:22) [25]


Есть браузер, который подключается к моему серверу, сервер анализирует запрос браузера и выдаёт ему запрошенные данные следующим образом :


procedure TMain.ServerSocketClientRead(Sender: TObject;
Socket: TCustomWinSocket);
var
...
Stream: TStream;
begin
...
Stream.LoadFromFile('C:\1.htm');
DATA.SendStream(Socket,Stream);
...
Stream.LoadFromFile('C:\2.htm');
DATA.SendStream(Socket,Stream);  

Socket.Close; Однако данные не успевают передаться клиенту, прежде чем произойдёт закрытие сокета в основном потоке
end;

procedure SendS(Par: Pointer);
var
 i: integer;
 buff: array[0..65536] of byte;
 p: ^TSendStreamParam;
 Socket: TCustomWinSocket;
begin
 try
   SendStreamCriticalSection.Enter;
   try
     p := Par;
     if not p.Socket.Connected then
       Exit;
     p.Stream.Position:=0;
     repeat
       i:=p.Stream.Read(buff,SizeOf(buff));
       while p.Socket.SendBuf(buff,i)=-1 do
     until (i=0)or(not p.Socket.Connected);
     p.Stream.Free;
   except
     //
   end;
 finally
   SendStreamCriticalSection.Leave;
 end;
end;

function TDATA.SendStream(Socket: TCustomWinSocket; Stream: TStream): Boolean;
var
 c: Cardinal;
begin
 SendStreamParam.Socket := Socket;
 SendStreamParam.Stream := TMemoryStream.Create;
 SendStreamParam.Stream.LoadFromStream(Stream);
 BeginThread(nil,100000,@SendS,@SendStreamParam,0,c);
end;


Как мне передать данные в браузер полностью, используя не блокирующийрежим TServerSocket-a? При этом в отдельный поток нужно брать только отсылку данных. Обработка запроса и формирование отсылаемой информации должны проходить в основном потоке


Сергей М.   (2008-04-08 12:22:00) [4]


> DelphiN!   (08.04.08 12:13) [24]


Какая-то каша у тебя в голове)

Излагай свой прикладной протокол инф.обмена - кто кому что передадает, в какой момент и при каких условиях.

Без его четкого понимания разговор на тему "когда закрывать соединение" лишен всякого смысла.


DelphiN!   (2008-04-08 12:13:00) [5]


> Сергей М. ©   (08.04.08 12:05) [23]
Я вообще-то о штатном методе SendStream веду речь...


Допустим моя процедура SendStream выглядит так, и использует штатный SendStream


//Отправка данных в отдельном потоке
procedure SendS(Par: Pointer);
var
 i: integer;
 buff: array[0..65536] of byte;
 p: ^TSendStreamParam;
 Socket: TCustomWinSocket;
begin
 try
   SendStreamCriticalSection.Enter;
   try
     if not p.Socket.Connected then
       Exit;
      p.Socket.SendStream(Stream);
   except
     //
   end;
 finally
   SendStreamCriticalSection.Leave;
 end;
end;

//Моя процедура SendStream
function TDATA.SendStream(Socket: TCustomWinSocket; Stream: TStream): Boolean;
var
 c: Cardinal;

 i: Integer;
 buff: array[0..1024] of byte;
begin
 SendStreamParam.Socket := Socket;
 SendStreamParam.Stream := TMemoryStream.Create;
 SendStreamParam.Stream.LoadFromStream(Stream);
 BeginThread(nil,100000,@SendS,@SendStreamParam,0,c);
end;



> Соединение следует закрывать не раньше чем будет вызван
> деструктор объекта-стрима, переданного параметром в метод
> SendStream


Так из OnClientRead процедура DATA.SendStream может вызываться несколько раз, и после каждого вызова она будет закрывать сокет? Тогда как второй вызов DATA.SendStream отошлет данные через закрытый сокет?


Сергей М.   (2008-04-08 12:05:00) [6]

Я вообще-то о штатном методе SendStream веду речь...


DelphiN!   (2008-04-08 11:59:00) [7]


> Сергей М. ©   (08.04.08 11:51) [21]


Наверное я плохо объяснил ...


procedure TMain.ServerSocketClientRead(Sender: TObject;
 Socket: TCustomWinSocket);
var
 ...
 Stream: TStream;
begin
 ...
 Stream.LoadFromFile('C:\1.htm');
 SendStream(Socket,Stream); // SendStream отсылает данные и закрывает сокет
 ...
 Stream.LoadFromFile('C:\2.htm');
 SendStream(Socket,Stream); // SendStream пытается отослать данные, но сокет то уже закрыт!

 Socket.Close; // Если закрывать сокет тут, то дочерний поток по отправке данных не успеет отослать все данные
end;

Так где закрывать сокет?


Сергей М.   (2008-04-08 11:51:00) [8]


> А как закрыть соединение вовремя


Соединение следует закрывать не раньше чем будет вызван деструктор объекта-стрима, переданного параметром в метод SendStream


DelphiN!   (2008-04-08 11:46:00) [9]


> Сергей М. ©   (08.04.08 10:35) [18]
>
>
> Потому что ты закрываешь соединение раньше чем поток передан
> полностью.
>


А как закрыть соединение вовремя, если процедура SendStream вызывается несколько раз из события ServerSocketClientRead, ведь мне нужно когда-то закрыть сокет, а когда процедура вызовется последний раз я не знаю и соответственно когда закрыть сокет тоже незнаю


> А каким боком тут FB и IBX ?


FB и IBX использовались когда я для каждого соединения делал один поток, а тут я решил только отсылку данных сделать в отдельном потоке, поэтому сейчас в отдельном потоке FB и IBX не используется


> han_malign ©   (08.04.08 10:52) [19]
>
>
> > SendStreamParam.Stream := Stream;
>
> SendStreamParam.Stream:= TMemoryStream.Create;
> SendStreamParam.Stream.LoadFromStream(Stream);
> - время жизни исходного потока какое?


Со Stream-ом понятно, спасибо, но когда закрывать сокет?
Исходный Stream живёт недолго. Основной поток(Thread) живёт всегда


han_malign   (2008-04-08 10:52:00) [10]


> SendStreamParam.Stream := Stream;

SendStreamParam.Stream:= TMemoryStream.Create;
SendStreamParam.Stream.LoadFromStream(Stream);
- время жизни исходного потока какое?


Сергей М.   (2008-04-08 10:35:00) [11]


> Почему не знаю


Потому что ты закрываешь соединение раньше чем поток передан полностью.

А каким боком тут FB и IBX ?


DelphiN!   (2008-04-08 10:32:00) [12]

Когда отсылаю скажем большую WEB страницу через SendStream, то на клиенте страница загружается только на половину. Почему не знаю ... Если отсылаю данные через        

p.Stream.Position:=0;
repeat
 i:=Stream.Read(buff,SizeOf(buff));
 while Socket.SendBuf(buff,i)=-1 do
   until i=0;


WEB страница отображается на клиенте в полном объёме, независимо от размера


Сергей М.   (2008-04-08 10:25:00) [13]


> DelphiN!   (08.04.08 10:18) [14]



> Стандартный SendStream отсылает большие объем данных по
> полностью


??


DelphiN!   (2008-04-08 10:24:00) [14]


> Сергей М. ©   (08.04.08 10:06) [9]


>
> > процедура SendStream
>
> Чем штатный метод SendStream не угодил ?


Стандартный SendStream отсылает большие объем данных по полностью


DelphiN!   (2008-04-08 10:18:00) [15]


> Сергей М. ©   (08.04.08 10:13) [13]


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


Сергей М.   (2008-04-08 10:13:00) [16]


> компоненты IBX и СУБД FireBird которые отказываются "правильно"
> работать в отдельных потоках
>


Ды ты что ?!

Неужели прямо так и говорят - "Отказываемся" ?)


DelphiN!   (2008-04-08 10:11:00) [17]


> Сергей М. ©   (08.04.08 10:06) [9]


TServerSocket в режиме stNonBlocking, а обслуживать каждого активного клиента в отдельном потоке не могу, так как при обработке использую компоненты IBX и СУБД FireBird которые отказываются "правильно" работать в отдельных потоках


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


> можно ли определять какой размер стека мне нужен динамически?


Это зависит от многих факторов.

В 1-ю очередь - от максимальной ожидаемой глубины вложенности вызовов п/программ в данном потоке.


DelphiN!   (2008-04-08 10:08:00) [19]

Простите грешного :) Установил размер стека статически ... А можно ли определять какой размер стека мне нужен динамически?


Сергей М.   (2008-04-08 10:06:00) [20]


> в дочернем потоке


За каким лешим нужно плодить потоки, если TServerSocket в режиме thread-blocking и так уже обслуживает каждого активного клиента в отдельном потоке ?


> процедура SendStream


Чем штатныйметод SendStream не угодил ?


Страницы:   1 2

Наверх

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