Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2005.07.11;
Скачать: CL | DM;

Вниз

Ошибка 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); // &#207;&#238;&#228;&#234;&#235;&#254;&#247;&#232;&#235;&#241;&#255; &#237;&#238;&#226;&#251;&#233; &#234;&#235;&#232;&#229;&#237;&#242;
        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 //&#209;&#238;&#231;&#228;&#224;&#229;&#236; &#239;&#243;&#235; &#239;&#238;&#242;&#238;&#234;&#238;&#226;
     IT := CreateInternalThread(GV, i);
     if IT <> nil then GV^.PullThread.Add(IT);
   end;
   //************************************************ // &#209;&#235;&#243;&#248;&#224;&#254;&#249;&#232;&#233; &#239;&#238;&#242;&#238;&#234;
   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;
Скачать: CL | DM;

Наверх




Память: 0.57 MB
Время: 0.062 c
1-1118444356
gans_2
2005-06-11 02:59
2005.07.11
как запретить редактирование отдельной ячейки StringGrid


1-1118916532
Oleg2
2005-06-16 14:08
2005.07.11
Controls на панели(TPanel)


3-1117305289
asker
2005-05-28 22:34
2005.07.11
Kak udalit fail s bazoj dannih??


1-1119555465
Diaskhan
2005-06-23 23:37
2005.07.11
VCL outlook panel


1-1119339737
pavel_guzhanov
2005-06-21 11:42
2005.07.11
Как преобразовать дату?