![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Ошибка AV в потоке [D6]
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 не угодил ?