![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Проблема с блок. сокетами!!!! [D5, WinXP]
SidDN © (2003-09-10 14:10:00)
Мастера ХЕЛП!!!
Пишу клиент-сервер на блок. сокетах. Проблема в том, что на одних машинах есть глюк, а на других нет. Глюк заключается в том, что первый раз клиент обменивается данными с сервером нормально, а потом перестает, т.е. не устанавливается соединение с сервером. Хотя на некоторых машинах (и локально на одной) всё впорядке.
Целый день долбаюсь. Оси везде WinXP. Может у кого есть идеи, могу привести код.
Digitman (2003-09-10 15:46:00) [41]
> при втором запросе это уже другой поток
не факт.
тот же поток м.б. взят объектом TServerWinSocket из кэша, с передачей ему параметром нового ClientSocket
Verg (2003-09-10 15:44:00) [42]
А по сути, мне почему-то кажется, что рыть надо в сторону эту:
> procedure TComIOThread.Show;
> begin
> if Assigned(DataShow)then DataShow(Data);
> end
SidDN (2003-09-10 15:44:00) [43]
Спасибо за объяснение.
Но в finally он действительно не заходит.
Кстати я закомментировал в блоке finally уничтожение сокета, и всё стало работать, в чём дело?
Verg (2003-09-10 15:37:00) [44]
> Ставил, не заходит.
Не может быть.
> Если можно, расскажи, плз.
Когда ты делашь шаг (без захода, т.е. F8) отладчик делает так:
Заменяет байт следующий за операцией вызова процедуры на прерывание отладчика (int 3) и пускает поток на выполнение, ожидая того самого прерывания. Дождавшись, восстанавливает тот самый байт. В данном случае внутри процедуры возникает исключение и поток никогда не попадает на инструкцию следующую за операцией вызова, а начинает выполнять цепочки finally, except. Ну вот ты и видишь этот эффект.
SidDN (2003-09-10 15:29:00) [45]
to Digitman © (10.09.03 15:24)
Но при втором запросе это уже другой поток и другой ClientSocket
to Verg © (10.09.03 15:25)
Ставил, не заходит.
Если можно, расскажи, плз.
Verg (2003-09-10 15:25:00) [46]
> При трассировке компилятор после этой строки
> ClientSocket.Active:=True;
> прекращает выполнение процедуры, в блок Finally не попадает
Это понятно, так и должно быть (именно при трассировке), если хочешь расскажу как и почему, но к данному вопросу это не относится.
Просто для проверки поставь точку останова (Ctrl+F8) на первом операторе в finally...
Digitman (2003-09-10 15:24:00) [47]
> ClientSocket.Address:=Address;
> ClientSocket.ClientType:=ctBlocking;
> ClientSocket.Port:=Port;
> ClientSocket.Active:=True; <- Вот после этого места
> происходит выход из процедуры
ничего подобного.
если в момент выполнения этого кода ClientSocket был Active, то
на любой из этих строчек (на первой же !)
ClientSocket.Address:=Address;
ClientSocket.ClientType:=ctBlocking;
ClientSocket.Port:=Port;
ты схлопочешь исключение, и до строчки
ClientSocket.Active:=True
даже дело не дойдет
SidDN (2003-09-10 15:20:00) [48]
При трассировке компилятор после этой строки
ClientSocket.Active:=True;
прекращает выполнение процедуры, в блок Finally не попадает
Verg (2003-09-10 15:13:00) [49]
А все, пардон, вижу есть там Stream:=nil
Verg (2003-09-10 15:10:00) [50]
Давай начнем с этого участка:
> ClientSocket.Active:=True;
> Stream:=TWinSocketStream.Create(ClientSocket.Socket,
> 30000);
Ты понимаешь, что если Active:=true вызовет исключение, то поток кинется выполнять
> finally
> ClientSocket.Active:=False;
> ClientSocket.Free;
> Stream.Free;> end;
Заметь: Stream - переменная в стеке (не поле объекта) и nil быть равна не обязана
SidDN (2003-09-10 15:07:00) [51]
To Verg
При первом запросе увеличивается сразу на 5!!! потом 3 убиваются, и с каждым новым запросом число потоков увеличивается на 1.
Мистика!
SidDN (2003-09-10 15:02:00) [52]
Из procedure TComIOThread.Execute
Verg (2003-09-10 15:02:00) [53]
> Resume не надо, в Create false передаётся
> constructor TComIOThread.Create;
> begin
> DataShow:=FDataShow;
> Data:=FData;
> Address:=FAddress;
> Port:=FPort;
> FreeOnTerminate:=True;
> inherited Create( CreateSuspended); - это?
> end;
увеличивается число потоков приложения
На сколько? На 2 или на 1, в смысле на каждый запрос?
Digitman (2003-09-10 15:01:00) [54]
> ClientSocket.Active:=True; <- Вот после этого места происходит
> выход из процедуры
из какой процедуры ?
SidDN (2003-09-10 14:54:00) [55]
Resume не надо, в Create false передаётся
Замечено было Task Manager-ом. С каждой попыткой запроса к серверу увеличивается число потоков приложения, хотя на других компах поток создавался и сразу по приходу ответа грохался.
Verg (2003-09-10 14:49:00) [56]
Не хватает Resume, ну ладно, где-то он все равно есть.
> Было замечено, что при глюках не уничтожается клиентский
> поток.
Каким образом это было замечено?
SidDN (2003-09-10 14:26:00) [57]
Было замечено, что при глюках не уничтожается клиентский поток.
И при повторных запросах к серверу при трассировке
ClientSocket.Address:=Address;
ClientSocket.ClientType:=ctBlocking;
ClientSocket.Port:=Port;
ClientSocket.Active:=True; <- Вот после этого места происходит выход из процедуры
А на других машинах, повторяюсь, всё проходит нормально.
SidDN (2003-09-10 14:18:00) [58]
Это сервак
TCommServerThreadNew=class(TServerClientThread)
public
procedure ClientExecute; override;
end;
{......}
procedure TCommServerThreadNew.ClientExecute;
var
Stream: TWinSocketStream;
s1,Buffer, strIn: string;
DataSize,nRead: Integer;
begin
Stream := TWinSocketStream.Create(ClientSocket, 5000);
while not Terminated and ClientSocket.Connected do
begin
Buffer:="";
strIn := "";
SetLength(Buffer, 64);
nRead := Stream.Read(Buffer[1], 64);
if nRead = 0 then
begin
ClientSocket.Close;
Exit;
end;
// Получаем длину пакета
SetLength (Buffer, nRead);
SetLength(s1, StrLen(PChar(Buffer))+1);
StrLCopy(@s1[1], PChar(Buffer), Length(s1)-1);
DataSize:=StrToInt(s1);
Delete(Buffer, 1, Length(s1));
StrIn := StrIn + Buffer;
while Length(StrIn)<DataSize do // Получаем весь пакет
begin
SetLength(Buffer, nRead);
nRead := Stream.Read(Buffer[1], nRead);
if nRead = 0 then
begin
ClientSocket.Close;
Break;
end;
SetLength (Buffer, nRead);
StrIn := StrIn + Buffer;
end;
if StrIn = "" then Exit else
begin
// Чё-то делаем, и отправляем ответ (в данном случае эту-же строку)
StrIn:=IntToStr(Length(StrIn))+#0+StrIn;
Stream.Write(StrIn[1],Length(StrIn));
end;
end;
Stream.Free;
end;
{....}
// Так сервак стартуем
ServerBlocked:=TServerSocket.Create(nil);
ServerBlocked.Port:=17785;
ServerBlocked.ServerType:=stThreadBlocking;
ServerBlocked.OnGetThread:=Self.OnGetThreadNew;
ServerBlocked.Active:=True;
{...}
procedure TForm1.OnGetThreadNew(Sender: TObject;
ClientSocket: TServerClientWinSocket;
var SocketThread: TServerClientThread);
begin
SocketThread := TCommServerThreadNew.Create(False, ClientSocket)
end;
Это клиент
TDataShow= procedure(StrIn:string)of object;
// Поток клиента
TComIOThread=class(TThread)
private
ClientSocket:TClientSocket;
Buffer:TMemoryStream;
InDataSize:integer;
Address:string;
Port:word;
Data:string;
protected
procedure Execute; override;
public
DataShow:TDataShow;
constructor Create(CreateSuspended: Boolean; FDataShow: TDataShow;FAddress:string;FPort:word;FData:string);
procedure Show;
end;
constructor TComIOThread.Create;
begin
DataShow:=FDataShow;
Data:=FData;
Address:=FAddress;
Port:=FPort;
FreeOnTerminate:=True;
inherited Create(CreateSuspended);
end;
procedure TComIOThread.Execute;
var
Stream:TWinSocketStream;
nRead,nRead1:integer;
TMP,s1:string;
begin
ClientSocket:=TClientSocket.Create(nil);
Stream:=nil;
try
ClientSocket.Address:=Address;
ClientSocket.ClientType:=ctBlocking;
ClientSocket.Port:=Port;
ClientSocket.Active:=True;
Stream:=TWinSocketStream.Create(ClientSocket.Socket, 30000);
ClientSocket.Socket.SendText(Data); // Посылаем запрос
if Stream.WaitForData(30000) then // Ждём ответ
begin
SetLength(TMP, 65535);
nRead1 := Stream.Read(TMP[1], 65535);
if nRead1 = 0 then
begin
ClientSocket.Close;
end;
SetLength (TMP, nRead1);
// Определяем размер данных
SetLength(s1, StrLen(PChar(TMP))+1);
StrLCopy(@s1[1], PChar(TMP), Length(s1)-1);
InDataSize:=StrToInt(s1);
Delete(TMP, 1, Length(s1));
Buffer:=TMemoryStream.Create;
Buffer.Write(TMP[1],Length(TMP));
while Buffer.Size<InDataSize do // Получаем остальные
begin
SetLength(TMP, nRead1);
nRead := Stream.Read(TMP[1], nRead1);
if nRead = 0 then
begin
ClientSocket.Close;
Break;
end;
Buffer.Write(TMP[1],nRead);
end;
SetLength(Data,Buffer.Size);
Buffer.Position:=0;
Buffer.Read(Data[1],Buffer.Size);
Buffer.Free;
Synchronize(Show);
end else
begin
// TimeOut
end;
finally
ClientSocket.Active:=False;
ClientSocket.Free;
Stream.Free;
end;
end;
procedure TComIOThread.Show;
begin
if Assigned(DataShow)then DataShow(Data);
end;
// Запуск клиента
st:="EXPENSE[A1,A2,R1,R2] COUNT[TEST1] PERIOD[08.09.03]";
TComIOThread.Create(False,DataShow,"192.168.0.77",17785, IntToStr(Length(st))+#0+st);
Digitman (2003-09-10 14:12:00) [59]
> могу привести код
приводи