Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Сети";
Текущий архив: 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); // &#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;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.56 MB
Время: 0.989 c
9-1112104351
Smab
2005-03-29 17:52
2005.07.11
Большие текстуры


1-1118590976
iskatel
2005-06-12 19:42
2005.07.11
памяти в память


14-1118649321
Stanislav
2005-06-13 11:55
2005.07.11
Установка компонент в Delphi2005


3-1116936756
aleliko
2005-05-24 16:12
2005.07.11
TADOBlobStream


14-1117717481
evvcom
2005-06-02 17:04
2005.07.11
Продолжение дискуссии "Как избежать гонок в потоках"





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский