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

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

Проблема с блок. сокетами!!!! [D5, WinXP]


Страницы:   1 2 3

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]


> могу привести код


приводи


Страницы:   1 2 3

Наверх

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