Форум: "Сети";
Текущий архив: 2005.07.11;
Скачать: [xml.tar.bz2];
ВнизОшибка 10038 - Объект не является сокетом Найти похожие ветки
← →
atruhin © (2005-04-07 11:06) [0]Вот тело процедуры Execute потока
while not Terminated do begin
New(IntPort);
Len:=SizeOf(FAddr);
IntPort^.Port:=Accept(FListenSocket,FAddr,Len);
if IntPort^.Port <> INVALID_SOCKET then begin
IntPort^.Time := Now;
EnterCriticalSection(GV^.CrsPortList);
try
GV^.IntPorts.Add(IntPort);
except
end;
LeaveCriticalSection(GV^.CrsPortList);
ReleaseSemaphore(GV^.NextThread, 1, nil);
end else begin
-- Вот здесь выдается ошибка 10038
LineInLog("Error - > "+IntTostr(WSAGetLastError));
Dispose(IntPort);
end;
end;
причем FListenSocket с начала выполнения потока, и во время ошибки не изменяется
← →
Digitman © (2005-04-07 11:11) [1]Accept() возвращает не номер порта, а хэндл вновь созданного гнезда
если Accept() вернула подобный отказ, это означает что FListenSocket не содержит корректное значение хэндла действительно созданного тобой и существующего на этот момент "слушающего" серверного гнезда
проверяй, что у тебя находится в FListenSocket на момент вызова ф-ции
← →
atruhin © (2005-04-07 11:34) [2]причем FListenSocket с начала выполнения потока, и во время ошибки не изменяется
Дело в том что все это работает и иногда возинает такая ошибка.
Я в разделе основная задавал вопрос про Access Violation видать это связано где то память портится :(
← →
Digitman © (2005-04-07 12:03) [3]
> atruhin © (07.04.05 11:34) [2]
> в разделе основная задавал вопрос про Access Violation
э-э-э ... не месил бы ты кислое с пресным ...
в дан.случае никакого AV нет, ф-ция просто отказала по причине некорректности значения 1-го аргумента
покажи, где, как и в какой момент ты создаешь слушающее гнездо ..
← →
atruhin © (2005-04-07 13:07) [4]Весь код
{ TAcceptThread }
constructor TAcceptThread.Create(_ListenSocket : TSocket; _GV : PGlobalVar);
begin
inherited Create(false);
FListenSocket := _ListenSocket;
GV:=_GV;
end;
procedure TAcceptThread.Execute;
var
FAddr: TSockAddrIn;
Len: Integer;
IntPort : PInternalPort;
begin
while not Terminated do begin
New(IntPort);
Len:=SizeOf(FAddr);
IntPort^.Port:=Accept(FListenSocket,FAddr,Len); // Ïîäêëþ÷èëñÿ íîâûé êëèåíò
if IntPort^.Port <> INVALID_SOCKET then begin
IntPort^.Time := Now;
EnterCriticalSection(GV^.CrsPortList);
try
GV^.IntPorts.Add(IntPort);
except
end;
LeaveCriticalSection(GV^.CrsPortList);
ReleaseSemaphore(GV^.NextThread, 1, nil);
end else begin
LineInLog("Error - > "+IntTostr(WSAGetLastError));
Dispose(IntPort);
end;
end;
end;
{ TPortMapper }
constructor TPortMapper.Create(_RemoteAddr : string; _RemotePort, _ListenPort : word);
begin
inherited Create(true);
New(GV);
GV^.RemoteAddr := _RemoteAddr;
GV^.RemotePort := _RemotePort;
GV^.ListenPort := _ListenPort;
SetPullThread(BegCountThread,MaxCountThread);
end;
destructor TPortMapper.Destroy;
begin
Dispose(GV);
inherited;
end;
procedure TPortMapper.SetPullThread(_MinThread, _MaxThread: word);
begin
MinThread := _MinThread;
MaxThread := _MaxThread;
end;
procedure TPortMapper.Execute;
var
i : integer;
TimeCr : TDateTime;
IT : TInternalThread;
FAddr: TSockAddrIn;
begin
GV^.ThreadPlaned :=0;
GV^.PortMapObj := Self;
GV^.IntPorts := TList.Create;
GV^.PullThread := TList.Create;
GV^.NextThread := CreateSemaphore(nil, 0, MaxCountThread, nil);
InitializeCriticalSection(GV^.CrsPortList);
GV^.EndWorkEvent:=CreateEvent(nil,true, false, nil);
for i:=1 to MinThread do begin //Ñîçäàåì ïóë ïîòîêîâ
IT := CreateInternalThread(GV, i);
if IT <> nil then GV^.PullThread.Add(IT);
end;
//************************************************ // Ñëóøàþùèé ïîòîê
FListenSocket := socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
if FListenSocket = INVALID_SOCKET then begin
MessageClient(msgWSAError, WSAGetLastError);
end else begin
FAddr.sin_family := PF_INET;
FAddr.sin_addr.s_addr := INADDR_ANY;
FAddr.sin_port := htons(GV^.ListenPort);
bind(FListenSocket, @FAddr, SizeOf(FAddr));
listen(FListenSocket, 100);
AcceptThread := TAcceptThread.Create(FListenSocket, GV);
//************************************************
while not Terminated do begin
Sleep(300);
end;
end;
SetEvent(GV^.EndWorkEvent);
//************************************************
if FListenSocket <> INVALID_SOCKET then begin
shutdown(FListenSocket,2);
closesocket(FListenSocket);
end;
AcceptThread.Free;
//************************************************
for i:=GV^.PullThread.Count-1 downto 0
do TInternalThread(GV^.PullThread[i]).Free;
CloseHandle(GV^.EndWorkEvent);
DeleteCriticalSection(GV^.CrsPortList);
CloseHandle(GV^.NextThread);
GV^.PullThread.Free;
GV^.IntPorts.Free;
end;
function TPortMapper.CreateInternalThread(_GV : PGlobalVar; _Num : word): TInternalThread;
begin
Result := TInternalThread.Create(_GV, _Num);
end;
← →
atruhin © (2005-04-07 13:11) [5]TGlobalVar = record
CrsPortList : TRTLCriticalSection;
IntPorts : TList;
EndWorkEvent : THandle;
ThreadPlaned : longint;
NextThread : THandle;
PullThread : TList;
PortMapObj : TObject;
RemoteAddr : string[255];
RemotePort, ListenPort : word;
end;
PGlobalVar = ^TGlobalVar;
TInternalPort = record
Port : TSocket;
Time : tDateTime;
end;
PInternalPort = ^TInternalPort;
← →
Verg © (2005-04-07 13:51) [6]Значит его кто-то закрывает. Например, TPortMapper
> //************************************************
> if FListenSocket <> INVALID_SOCKET then begin
> shutdown(FListenSocket,2);
> closesocket(FListenSocket);
> end;
> ;
Наверняка вызовет WSAENOTSOCK у AcceptThread, а следующий за ним AcceptThread.Free приведет вообще к непредсказуемым последствиям, т.к. к этому моменту не получено никакой гарантии, что поток AcceptThread завершил работу.
← →
Verg © (2005-04-07 13:53) [7]И кто такой TInternalThread ?
← →
Digitman © (2005-04-07 13:58) [8]что-то я нигде не вижу WSAStartup/Cleanup
← →
atruhin © (2005-04-07 14:57) [9]unit PortMapper;
interface
{$define pmdebug}
{$define debug}
uses
SysUtils,
Classes,
Windows,
WinSock2;
const
MaxCountThread = 100; // Максимальное кол-во потоков в пуле
BegCountThread = 2; // Начальное кол-во потоков в пуле
AliveTimeout = 60000; // Таймаут отсутствия активности сокета
SendTimeoutSec = 10;
BufferSizeOut = 64000; // Максимальный размер накапливаемых данных
ThreadMaxTimeOut = (7E-4)/30; // Время простоя сокета в очереди, приводящее
// к увеличению пула.
const
erNotListen = "Can""t open listening port";
erNoCreateServer = "Can""t create server socket";
erAny = "Any Error";
msgWSAError = -1;
msgNoRightClient = 2; // Нет прав на подключение к прокси
msgBufferSizeOut = 3; // Превышение размера буфера
msgNoRightHostConnect = 4; // Нет прав на подключение к хосту
msgNoConnect = 5; // Ошибка подключения к хосту
msgSendTimeout = 6;
msgRecvTimeOut = 1; // Таймаут соеденения
msgHeaderError = 7;
type
TData = array of char;
PData = ^TData;
TGlobalVar = record
CrsPortList : TRTLCriticalSection; // Защщита обращения к IntPorts
IntPorts : TList; // Список акцептированных, необработанных сокетов
EndWorkEvent : THandle; // Событие завершения работы программы
ThreadPlaned : longint; // Кол-во работающих потоков
NextThread : THandle; // Семафор пула потоков
PullThread : TList; // Пул потоков
PortMapObj : TObject;
RemoteAddr : string[255];
RemotePort, ListenPort : word;
end;
PGlobalVar = ^TGlobalVar;
TInternalPort = record
Port : TSocket;
Time : tDateTime;
end;
PInternalPort = ^TInternalPort;
TMyExcept = class(Exception);
TInternalThread = class(TThread)
NumberThread : word; // Номер потока в пуле (для отладки)
GV : PGlobalVar; // Глобальные переменные
//*************
InternalSocket, ExternalSocket : TSocket;
Redirect : boolean;
InternalSockAddrIn : TSockAddrIn; // Информация о клиентском подключении
InternalData, ExternalData : TData; // Данные от сокетов
InternalLen, ExternalLen : integer; // Длинна данных
SocketError : boolean;
public
constructor Create(_GV : PGlobalVar; _Num : word); reintroduce;
procedure Execute;override;
//**** ВНИМАНИЕ! Следующие методы должны быть потокобезопасными
procedure Complete; virtual;
// Вызывается при коннекте клиента проверяет права клиента на коннект
function ClientConnect : boolean; virtual;
// Вызывается в конце соединения, получает общую статистку о сеансе
procedure EndConnect; virtual;
// Вызывается перед подключением к удаленному хосту true - если адрес разрешен
function HostConnect(Host : string; Port : word) : boolean; virtual;
// Если RemoteAddr="" или RemotePort="" должна их проинициализировать и вернуть управление
// на каком то этапе :) записывает InternalLen байт из InternalData в ExternalSocket
procedure IsInternalRead(LenRecv : integer); virtual;
// записывает ExternalLen байт из ExternalData в InternalSocket
procedure IsExternalRead(LenRecv : integer); virtual;
// Непосредственная передача данных в сокет
function SendDataToSocket(var Sct : TSocket; var Data : TData; var LenData : integer):boolean;
procedure OpenExternalSocket(Host : string; Port : word);
procedure MessageClient(Msg, MsgDetail : integer); virtual;
private
fCurrHost : string;
fCurrPort : word;
protected
property CurrentHost : string read fCurrHost write fCurrHost;
property CurrentPort : word read fCurrPort write fCurrPort;
end;
TAcceptThread=class(TThread)
GV : PGlobalVar;
private
FListenSocket : TSocket;
protected
procedure Execute;override;
public
constructor Create(_ListenSocket : TSocket; _GV : PGlobalVar);reintroduce;
end;
TPortMapper = class(TThread)
GV : PGlobalVar;
FListenSocket : TSocket;
AcceptThread : TAcceptThread;
MinThread, MaxThread : word;
protected
procedure Execute;override;
public
constructor Create(_RemoteAddr : string; _RemotePort, _ListenPort : word );reintroduce;
destructor Destroy; override;
procedure SetPullThread(_MinThread, _MaxThread : word);
function CreateInternalThread(_GV : PGlobalVar; _Num : word) : TInternalThread; virtual;
procedure MessageClient(Msg, MsgDetail : integer); virtual;
end;
{$ifdef debug}
procedure LineInLog(S : string);
var
F : textfile;
{$endif}
implementation
{ TInternalThread }
constructor TInternalThread.Create(_GV : PGlobalVar; _Num : word);
begin
NumberThread := _Num;
Gv:=_GV;
inherited Create(false);
end;
procedure TInternalThread.Complete;
const
MAX_PACKET_SIZE = 4096*2;
var
Hs : array [0..3] of THandle;
WaitResult : DWord;
EvCount : integer;
NetworkEvents:TWSANetworkEvents;
arg : u_long;
function DataRead(Sct : TSocket; var Data : TData; var LenData : integer) : integer;
var
Len : integer;
buff : array [0..MAX_PACKET_SIZE] of char;
begin
Result := 0;
Len := Recv(Sct, buff[0], MAX_PACKET_SIZE, 0);
if (Len = SOCKET_ERROR) then begin
MessageClient(msgWSAError, WSAGetLastError);
exit;
end;
if Len = 0 then exit;
ReallocMem(Data, LenData + Len);
Move(Buff[0], Data[LenData], Len);
inc(LenData, Len);
if LenData > BufferSizeOut then MessageClient(msgBufferSizeOut, 0);
Result := Len;
end;
begin
SocketError := false;
ExternalSocket := INVALID_SOCKET;
fCurrHost := GV^.RemoteAddr;
fCurrPort := GV^.RemotePort;
Redirect := fCurrHost <> "";
InternalData := nil;
ExternalData := nil;
InternalLen := 0;
ExternalLen := 0;
EvCount := 2;
Hs[0] := GV^.EndWorkEvent;
Hs[1] := WSACreateEvent;
Hs[2] := WSA_INVALID_EVENT;
repeat
WSAEventSelect(InternalSocket, Hs[1], FD_READ or FD_CLOSE); // ожидаем внутеренний сокет
if EvCount = 3 then begin
WSAEventSelect(ExternalSocket, Hs[2], FD_READ or FD_CLOSE); // внешний
end;
WaitResult := WaitForMultipleObjects(EvCount, @Hs[0], false, AliveTimeout);
case WaitResult of
WAIT_FAILED, // неправильный вызов функции (неверный описатель?)
WAIT_OBJECT_0 + 0 : break; // Окончание работы
WAIT_TIMEOUT: begin
{$ifdef pmdebug}LineInLog("TimeOut - " + inttostr(NumberThread));{$endif}
MessageClient(msgRecvTimeout, 0);
break;
end;
WAIT_OBJECT_0 + 1 : begin
WSAEnumNetworkEvents(InternalSocket, Hs[1], @NetworkEvents);
if NetworkEvents.lNetworkEvents and FD_Read>0 then
← →
atruhin © (2005-04-07 14:59) [10]if NetworkEvents.iErrorCode[FD_Read_Bit]=0 then begin // Пришли данные
IsInternalRead(DataRead(InternalSocket, InternalData, InternalLen));
if SocketError then break;
if (ExternalSocket <> INVALID_SOCKET)and(Hs[2] = WSA_INVALID_EVENT) then begin
Hs[2] := WSACreateEvent;
EvCount := 3;
end;
end else break;
if NetworkEvents.lNetworkEvents and FD_Close>0 then begin
IOCtlSocket(InternalSocket, FIONRead, arg);
while arg > 0 do begin
IsInternalRead(DataRead(InternalSocket, InternalData, InternalLen));
if SocketError then break;
IOCtlSocket(InternalSocket, FIONRead, arg);
end;
break;
end; {}
end;
WAIT_OBJECT_0 + 2 : begin
WSAEnumNetworkEvents(ExternalSocket, Hs[2], @NetworkEvents);
if NetworkEvents.lNetworkEvents and FD_Read>0 then
if NetworkEvents.iErrorCode[FD_Read_Bit]=0 then begin // Пришли данные
IsExternalRead(DataRead(ExternalSocket, ExternalData, ExternalLen));
if SocketError then break;
end else break;
if NetworkEvents.lNetworkEvents and FD_Close>0 then begin
IOCtlSocket(ExternalSocket, FIONRead, arg);
while arg > 0 do begin
IsExternalRead(DataRead(ExternalSocket, ExternalData, ExternalLen));
if SocketError then break;
IOCtlSocket(ExternalSocket, FIONRead, arg);
end;
break;
end;
end;
end;
until SocketError;
EndConnect; // Здесь делаем лог.
if Hs[1] <> WSA_INVALID_EVENT then WSACloseEvent(Hs[1]);
if Hs[2] <> WSA_INVALID_EVENT then WSACloseEvent(Hs[2]);
if ExternalSocket <> INVALID_SOCKET then begin
{$ifdef pmdebug} LineInLog("Ext disconnect - "+IntToStr(NumberThread)); {$endif}
shutdown(ExternalSocket, SD_BOTH);
CloseSocket(ExternalSocket);
ExternalSocket := INVALID_SOCKET;
end;
{$ifdef pmdebug} LineInLog("Int disconnect - "+IntToStr(NumberThread)); {$endif}
if InternalSocket <> Invalid_SOCKET then begin
shutdown(InternalSocket, SD_BOTH);
CloseSocket(InternalSocket);
InternalSocket := Invalid_SOCKET;
end;
if ExternalData <> nil then FreeMem(ExternalData);
if InternalData <> nil then FreeMem(InternalData);
end;
procedure TInternalThread.OpenExternalSocket(Host : string; Port : word);
var
Addr:TSockAddr;
he:PHostEnt;
S : string;
begin
if (Host = "")or(Port = 0) then exit;
if ExternalSocket <> INVALID_SOCKET then begin
{$ifdef pmdebug} LineInLog("Ext disconnect - "+IntToStr(NumberThread)); {$endif}
shutdown(ExternalSocket, SD_BOTH);
CloseSocket(ExternalSocket);
ExternalSocket := INVALID_SOCKET;
end;
if not HostConnect(Host, Port) then begin // Проверяем доступ к URL
MessageClient(msgNoRightHostConnect, 0); exit;
end;
// Открываем внешний сокет
ExternalSocket:=socket(PF_INET, SOCK_STREAM, IPPROTO_IP);
if ExternalSocket = Invalid_SOCKET then exit;
Addr.sin_family:=PF_INET;
Addr.sin_addr.s_addr :=inet_addr(PChar(Host));
if Addr.sin_addr.s_addr = $FFFFFFFF then begin
he:=GetHostByName(PChar(Host));
if Assigned(he) then begin
S := inet_ntoa(PInAddr(he.h_addr_list^)^);
Addr.sin_addr.s_addr :=inet_addr(PChar(S));
end;
end;
if Addr.sin_addr.s_addr <> $FFFFFFFF then begin
Addr.sin_port := htons(Port);
if connect(ExternalSocket, @Addr, SizeOf(Addr)) <> SOCKET_ERROR then begin
CurrentHost := Host;
CurrentPort := Port;
exit;
end;
end;
MessageClient(msgNoConnect, 0);
CloseSocket(ExternalSocket);
ExternalSocket := INVALID_SOCKET;
end;
function TInternalThread.SendDataToSocket(var Sct : TSocket; var Data : TData; var LenData : integer):boolean;
var
Offs, Len, res : longint;
FDSet:TFDSet;
TV : TTimeVal;
begin
Result := false;
if LenData <=0 then exit;
if Sct = INVALID_SOCKET then exit;
Offs := 0;
tV.tv_sec := SendTimeoutSec;
tv.tv_usec := 0;
repeat
FD_Zero(FDSet);
FD_Set(Sct,FDSet);
// Проверка готовности сокетов
Res := Select(0,nil,@FDSet,nil,@tv);
if Res = 0 then begin
MessageClient(msgSendTimeout, 0);
exit;
end;
if Res > 0 then begin
if FD_IsSet(Sct,FDSet) then begin
if LenData > 4096 then Len := 4096 else Len := LenData;
Len := Send(Sct, Data[Offs], Len, 0);
if (Len <> SOCKET_ERROR)and(Len > 0) then begin
inc(Offs, Len);
dec(LenData, Len);
end else begin
MessageClient(msgWSAError, WSAGetLastError);
exit;
end;
end;
end else begin
MessageClient(msgWSAError, WSAGetLastError);
exit;
end;
until LenData = 0;
Result := LenData = 0;
end;
procedure TInternalThread.IsExternalRead(LenRecv : integer);
begin
SendDataToSocket(InternalSocket, ExternalData, ExternalLen);
end;
procedure TInternalThread.IsInternalRead(LenRecv : integer);
begin
if (Redirect)and(ExternalSocket = INVALID_SOCKET)
then OpenExternalSocket(GV^.RemoteAddr, GV^.RemotePort);
if ExternalSocket <> INVALID_SOCKET
then SendDataToSocket(ExternalSocket, InternalData, InternalLen);
end;
procedure TInternalThread.Execute;
var
Hs : array [0..3] of THandle;
WaitResult : DWord;
IP : PInternalPort;
Size : integer;
begin
{$ifdef pmdebug} LineInLog("Start thread - "+IntToStr(NumberThread)); {$endif}
Hs[0]:=GV^.EndWorkEvent; // Внешнее завершение работы потока
Hs[1]:=GV^.NextThread; // Сработал семафор - обработать очередной запрос
while not Terminated do begin
WaitResult := WaitForMultipleObjects(2, @Hs[0], false, INFINITE);
case WaitResult of
WAIT_FAILED, // неправильный вызов функции (неверный описатель?)
WAIT_OBJECT_0 + 0 : break; // Окончание работы
WAIT_OBJECT_0 + 1 : begin // Поток стал планируемым
InterlockedExchangeAdd( @GV^.ThreadPlaned, 1);
EnterCriticalSection(GV^.CrsPortList);
if GV^.IntPorts.Count > 0 then begin
IP:= GV^.IntPorts[0]; // Извлекаем из очереди порт для обработки
GV^.IntPorts.Delete(0);
end else IP := nil;
LeaveCriticalSection(GV^.CrsPortList);
if IP <> nil then begin
Size := Sizeof(InternalSockAddrIn);
if getpeername( IP^.Port, InternalSockAddrIn, Size) = 0 then begin
InternalSocket := IP^.Port;
if ClientConnect then Complete // Если коннект разрешен обрабатываем запрос
else MessageClient(msgNoRightClient, 0); // Иначе посылаем отказ клиенту
end;
Dispose(IP);
end;
InterlockedExchangeAdd( @GV^.ThreadPlaned, -1);
end;
end;
end;
end;
← →
atruhin © (2005-04-07 15:01) [11]procedure TInternalThread.EndConnect;
begin
end;
function TInternalThread.ClientConnect: boolean;
{$ifdef pmdebug} var ClientIP : string; {$endif}
begin
{$ifdef pmdebug}
ClientIP := inet_ntoa(InternalSockAddrIn.Sin_Addr);
LineInLog("Connect from - "+ ClientIP+" NumberThread - "+ IntToStr(NumberThread));
{$endif}
Result := true;
end;
function TInternalThread.HostConnect(Host : string; Port : word) : boolean;
begin
{$ifdef pmdebug} LineInLog("Remote address - " + Host); {$endif}
Result := true;
end;
procedure TInternalThread.MessageClient(Msg, MsgDetail : integer);
begin
SocketError := true;
end;
{ TAcceptThread }
constructor TAcceptThread.Create(_ListenSocket : TSocket; _GV : PGlobalVar);
begin
inherited Create(false);
FListenSocket := _ListenSocket;
GV:=_GV;
end;
procedure TAcceptThread.Execute;
var
FAddr: TSockAddrIn;
Len: Integer;
IntPort : PInternalPort;
begin
while not Terminated do begin
New(IntPort);
Len:=SizeOf(FAddr);
IntPort^.Port:=Accept(FListenSocket,FAddr,Len); // Подключился новый клиент
if IntPort^.Port <> INVALID_SOCKET then begin
IntPort^.Time := Now;
EnterCriticalSection(GV^.CrsPortList);
try
GV^.IntPorts.Add(IntPort);
except
end;
LeaveCriticalSection(GV^.CrsPortList);
ReleaseSemaphore(GV^.NextThread, 1, nil);
end else begin
LineInLog("Error - > "+IntTostr(WSAGetLastError));
Dispose(IntPort);
end;
end;
end;
{ TPortMapper }
constructor TPortMapper.Create(_RemoteAddr : string; _RemotePort, _ListenPort : word);
begin
inherited Create(true);
New(GV);
GV^.RemoteAddr := _RemoteAddr;
GV^.RemotePort := _RemotePort;
GV^.ListenPort := _ListenPort;
SetPullThread(BegCountThread,MaxCountThread);
end;
destructor TPortMapper.Destroy;
begin
Dispose(GV);
inherited;
end;
procedure TPortMapper.SetPullThread(_MinThread, _MaxThread: word);
begin
MinThread := _MinThread;
MaxThread := _MaxThread;
end;
procedure TPortMapper.Execute;
var
i : integer;
TimeCr : TDateTime;
IT : TInternalThread;
FAddr: TSockAddrIn;
begin
GV^.ThreadPlaned :=0;
GV^.PortMapObj := Self;
GV^.IntPorts := TList.Create;
GV^.PullThread := TList.Create;
GV^.NextThread := CreateSemaphore(nil, 0, MaxCountThread, nil);
InitializeCriticalSection(GV^.CrsPortList);
GV^.EndWorkEvent:=CreateEvent(nil,true, false, nil);
for i:=1 to MinThread do begin //Создаем пул потоков
IT := CreateInternalThread(GV, i);
if IT <> nil then GV^.PullThread.Add(IT);
end;
//************************************************ // Слушающий поток
FListenSocket := socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
if FListenSocket = INVALID_SOCKET then begin
MessageClient(msgWSAError, WSAGetLastError);
end else begin
FAddr.sin_family := PF_INET;
FAddr.sin_addr.s_addr := INADDR_ANY;
FAddr.sin_port := htons(GV^.ListenPort);
bind(FListenSocket, @FAddr, SizeOf(FAddr));
listen(FListenSocket, 100);
AcceptThread := TAcceptThread.Create(FListenSocket, GV);
//************************************************
while not Terminated do begin
Sleep(300);
end;
end;
SetEvent(GV^.EndWorkEvent);
//************************************************
if FListenSocket <> INVALID_SOCKET then begin
shutdown(FListenSocket,2);
closesocket(FListenSocket);
end;
AcceptThread.Free;
//************************************************
for i:=GV^.PullThread.Count-1 downto 0
do TInternalThread(GV^.PullThread[i]).Free;
CloseHandle(GV^.EndWorkEvent);
DeleteCriticalSection(GV^.CrsPortList);
CloseHandle(GV^.NextThread);
GV^.PullThread.Free;
GV^.IntPorts.Free;
end;
function TPortMapper.CreateInternalThread(_GV : PGlobalVar; _Num : word): TInternalThread;
begin
Result := TInternalThread.Create(_GV, _Num);
end;
procedure TPortMapper.MessageClient(Msg, MsgDetail: integer);
begin
end;
{$ifdef debug}
procedure LineInLog(S : string);
begin
Writeln(S);
Writeln(F, S);
end;
initialization
AssignFile(F, "log.log");
rewrite(f);
finalization
closefile(f);
{$endif}
end.
← →
atruhin © (2005-04-07 15:11) [12]>>Verg © (07.04.05 13:51) [6]
>>Наверняка вызовет WSAENOTSOCK у AcceptThread,
Для этого и вызывается, закрытие сокета - окончание работы слушающей нити
>>а следующий за ним AcceptThread.Free
Free вызывает Destroy он ждет завершения работы
destructor TThread.Destroy;
begin
if (FThreadID <> 0) and not FFinished then
begin
Terminate;
if FCreateSuspended then
Resume;
WaitFor;
end;
>>Digitman © (07.04.05 13:58) [8]
>>WSAStartup/Cleanup
В главном модуле WSAStartup/Cleanup и создание объекта PortMap
Дело в том что в целом модуль работает, но при нагрузке раз в несколько часов происходят ошибки.
Бьюсь над этим уже 2 дня.
← →
Digitman © (2005-04-07 15:58) [13]
> Для этого и вызывается, закрытие сокета - окончание работы
> слушающей нити
ну а что ж ты удивляешься тогда ?
слушающая нить "висит" на блокирующем accept"те, в это время другая нить закрывает слушающее гнездо ... разумеется accept тут же вернет управление с соотв.отказом !
> В главном модуле WSAStartup/Cleanup
строго говоря, для совмести с различными версиями и реализациями Winsock-ядра WSAStartup/Cleanup следовало бы делать для КАЖДОГО созданного гнезда, как слушающего, так и неявно создаваемого ф-цией accept() при ее успешном завершении
посмотри как это делается в scktcomp.pas
← →
atruhin © (2005-04-08 10:08) [14]>>ну а что ж ты удивляешься тогда ?
Дак это происходит только при завершении работы всей программы.
Т.е. поток TPortMapper перед завершением завершает слушающий поток и все клиентские потоки.
>>WSAStartup/Cleanup следовало бы делать для КАЖДОГО созданного >>гнезда
посмотрю, хотя первый раз о таком услышал.
← →
Digitman © (2005-04-08 10:21) [15]
> Дак это происходит только при завершении работы всей программы
значит где-то еще происходит, а не только по завершению
← →
atruhin © (2005-04-08 10:40) [16]В том то и дело что происходит только при завершениии основного потока. Код выше.
if FListenSocket <> INVALID_SOCKET then begin
shutdown(FListenSocket,2);
closesocket(FListenSocket);
end;
AcceptThread.Free;
а получается что поток AcceptThread продолжает работать но в каждой итерации цикла ошибка 10038
Вообще вчера немного причесывал и оптимизировал код. Сегодня за пол дня ошибки не было. Посмотрю дальше.
← →
Digitman © (2005-04-08 11:19) [17]твой акцепт-тред должен немедленно завершаться не только по обнаружению флага терминирования, но и при обнаружении упомянутого отказа в акцепт-ф-ции
Страницы: 1 вся ветка
Форум: "Сети";
Текущий архив: 2005.07.11;
Скачать: [xml.tar.bz2];
Память: 0.56 MB
Время: 0.042 c