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

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

Многопоточный сервер на чистом API


Страницы:   1 2

+koha ©   (2008-08-22 12:49:00) 

Прошу модераторов не банить ветку как эту http://www.delphimaster.ru/cgi-bin/forum.pl?id=1218807638&n=4.
Просто перед хотел фраернуться перед кентами. Ну, вот скажите зачем трою нужен сервер да еще и мульти поточный? глупость.
Увидел мини веб-сервер размером 10кб. http://miniwebsvr.sourceforge.netрешил что-нибудь подобное сотворить на Delphi, а то говорят, что на нем такие миниатюрные вещи нельзя сотворить, ну типа нужен только СИ. Хочу опровергнуть это Делфа нихрена не хуже.

Немного усовершенствовал код, но все же будет вопрос:
Действительно ли вызов функции BeginThread() в Delphi приводит к утечке памяти?
И в этом приведенном коде она возможна?
Ну може кто еще чего подскажет?

unit TCP;

interface
Uses Windows, SysUtils, WinSock, SockErr, MsgLog;

Type
  PClientInfo = ^TClientInfo;
  TClientInfo = Record
    ClientSocket : TSocket;
    ClientAddr   : sockaddr_in;
    hClientThr   : THandle;
    ClientThrId  : Integer;
  end;

Type TThrCmd = (TC_READ, TC_WRITE, TC_STOP_SERVER, TC_STOP_CLIENT, TC_ERROR);

Function StartTCPServer(Port: Integer): Boolean;
Function StopTCPServer: Boolean;
Procedure TCPThreadProc(Param: Pointer);
Procedure TCPClientThreadProc(Param: Pointer);
Procedure AcceptProc(Param: Pointer);

Var
 hTCPThread  : Thandle;
 TCPThreadId : LongWord;
 WData       : TWSAData;
 SockListen  : TSocket;
 LocalAddr   : sockaddr_in;
 hAcceptThr  : THandle;
 AcceptThrId : LongWord;
 ClientInfoArray  : array of PClientInfo;
 MultipleThrArray : Array[1..MAXIMUM_WAIT_OBJECTS] of Thandle;
 CS_REC           : TRTLCriticalSection;

Const
 WM_NULL = $0000;
 WM_APP  = $8000;
 PM_NOREMOVE = 0;
 NET_MESSAGE = WM_USER+1;

implementation

function DeleteClientInfo(Num: integer): Integer;
var
 Count: integer;
begin
 try
   EnterCriticalSection(CS_REC);
   Count := length(ClientInfoArray);
   if (Num < 0) or (Num > Count) then Exit;
   Dispose(ClientInfoArray[num]);
   System.Move(ClientInfoArray[num+1],ClientInfoArray[num],(Count-num)*SizeOf(Pointer));
   SetLength(ClientInfoArray, Pred(Num));
 finally
   LeaveCriticalSection(CS_REC);
 end;
end;

Function StartTCPServer(Port: Integer): Boolean;
Var
 Err: Integer;
begin
 Result := True;
 if Not WSAStartup(MakeWord(1,1),WData) = 0 then begin
   SendDebugMsg('Err: (WSAStartup 0) WSAGetLastError: '+SockErrToStr(WSAGetLastError));
   Result := false;
   Exit;
 end;
 SockListen := Socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
 if SockListen = INVALID_SOCKET then begin
   SendDebugMsg('Error: Socket > WSAGetLastError: '+SockErrToStr(WSAGetLastError));
   Result := false;
   Exit;
 end;
 LocalAddr.sin_addr.S_addr := htonl(INADDR_ANY);
 LocalAddr.sin_family      := AF_INET;
 LocalAddr.sin_port        := htons(Port);
 if bind(SockListen, LocalAddr, sizeOf(LocalAddr)) = SOCKET_ERROR then begin
   SendDebugMsg('bind() Error: '+SockErrToStr(WSAGetLastError));
   Result := false;
   Exit;
 end;
 if Listen(SockListen,MAXIMUM_WAIT_OBJECTS) = SOCKET_ERROR then begin
   SendDebugMsg('Listen() Error: ' + SockErrToStr(WSAGetLastError));
   Result := false;
   Exit;
 end;
 hTCPThread := BeginThread(Nil,0, Addr(TCPThreadProc), 0,0, TCPThreadId);
 if hTCPThread = 0 then begin
   SendDebugMsg('Error: hTCPThread = 0 GLE: '+IntToStr(GetLastError));
   Result := False;
   Exit;
 end;
end;

Function StopTCPServer: Boolean;
begin
 Result:=false;
 if hTCPThread = Nil then Exit;
 PostThreadMessage(hTCPThread,NET_MESSAGE,integer(TC_STOP_SERVER),0);
 //Пока Без доп. проверки действительно ли остановился сервер или вышел таймаут
 while WaitForSingleObject(hTCPThread,600000) = WAIT_TIMEOUT do begin
   Sleep(50);
 end;
 Result:=True;
end;

Procedure TCPThreadProc(Param: Pointer);
Var
 Msg: TMsg;
begin
 try
   InitializeCriticalSection(CS_REC);
   hAcceptThr:=BeginThread(Nil,0,Addr(AcceptProc),Pointer(SockListen),0,AcceptThrId );
   if hAcceptThr = 0 then begin
     SendDebugMsg('Error: (hProc = 0) GLE: '+IntToStr(GetLastError));
     Exit;
   end;
   While true do begin
     if PeekMessage(Msg,hTCPThread, WM_NULL, WM_APP, PM_NOREMOVE) then begin
       GetMessage(Msg, 0, 0, 0);
       DispatchMessage(msg);
       Case TThrCmd(MSG.wParam) of
         TC_WRITE       : SendDebugMsg('MSG.wParam = TC_WRITE');
         TC_STOP_SERVER : SendDebugMsg('MSG.wParam = TC_STOP_SERVER');
         TC_STOP_CLIENT : SendDebugMsg('MSG.wParam = TC_STOP_CLIENT');
         TC_ERROR       : SendDebugMsg('MSG.wParam = TC_ERROR');
       end;
     end;
     Sleep(50);
   end;  
 finally
   DeleteCriticalSection(CS_REC);
 end;
end;

Procedure TCPClientThreadProc(Param: Pointer);
Var
 Err        : Integer;
 Buff       : Array[1..1024] of Char;
 Command    : String;
begin
 While True do begin
   FillChar(Buff, 1024, 0);
   Err := Recv(PClientInfo(Param).ClientSocket, Buff, 1024, 0);
   if Err = SOCKET_ERROR then begin
     SendDebugMsg(IntToStr(PClientInfo(Param).ClientThrId)
                  +' Err: TCPClientThreadProc Recv = '+SockErrToStr(WSAGetLastError));
     PostThreadMessage(TCPThreadId, NET_MESSAGE, Integer(TC_ERROR),PClientInfo(Param)^.ClientThrId);
     Exit;
   end;
   Command := StrPas(PChar(@Buff));
   if Command = '' then  begin
     CloseSocket(PClientInfo(Param)^.ClientSocket);
     Exit;
   end;
   SendDebugMsg('ComStr = '+Command+' '+IntToStr(Length(Command)));
   {=================================
     Command section                
    =================================}
   if Command = 'CLOSE_SESSION' then
     PostThreadMessage(hTCPThread, NET_MESSAGE, Integer(TC_STOP_CLIENT), PClientInfo(Param).ClientSocket);
 end;
end;

Procedure AcceptProc(Param: Pointer);
Var
 Size        : Integer;
 ClientThrId : Cardinal;
 hClientThr  : THandle;
 ClientAddr  : SockAddr_in;
 ClientInfo  : PClientInfo;
 Num         : Integer;
begin
 While True do begin
   New(ClientInfo);
   FillChar(ClientInfo^,SizeOf(TClientInfo), 0);
   Size := SizeOf(ClientAddr);
   ClientInfo.ClientSocket := accept(TSocket(Param),@ClientAddr, @Size);
   if ClientInfo.ClientSocket = INVALID_SOCKET then begin
     SendDebugMsg('Err: accept WSA_GLE: '+SockErrToStr(WSAGetLastError));
     PostThreadMessage(TCPThreadId,NET_MESSAGE,Integer(TC_ERROR),0);
     CloseSocket(ClientInfo.ClientSocket);
     Dispose(ClientInfo);
     Continue;
   end;
   try
     EnterCriticalSection(CS_REC);
     Num := Length(ClientInfoArray);
     SetLength(ClientInfoArray, Num+1);
     ClientInfo.ClientAddr := ClientAddr;    
     hClientThr := BeginThread(Nil,0,Addr(TCPClientThreadProc),ClientInfoArray[Num],CREATE_SUSPENDE D,ClientThrId);
     if hClientThr = 0 then begin
       SendDebugMsg('BeginThread err:'+IntToStr(GetLastError));
       CloseSocket(ClientInfo^.ClientSocket);
       Dispose(ClientInfo);
       SetLength(ClientInfoArray, num);
       Continue;
     end;
     ClientInfo.hClientThr  := hClientThr;
     ClientInfo.ClientThrId := ClientThrId;
     ClientInfoArray[Num]   := ClientInfo;
     ResumeThread(ClientInfo.hClientThr);
   finally
     LeaveCriticalSection(CS_REC);
   end;
 end;
end;

end.


+koha   (2008-08-22 13:12:00) [21]

> А уничтожать этот объект - закрывать полученный при создании хэндл - кто за > тебя будет, Пушкин ?

Хедлы потоков-клиентов закрывать будет поток TCPThreadProc по полученным PostThreadMessage(hTCPThread, NET_MESSAGE, Integer(TC_STOP_CLIENT), PClientInfo(Param).ClientSocket)от клиентов сообщениям или самостоятельно при своем завершении. Просто код не влазит в размер 7168 бт. так на форуме определено, я код допишу и покажу.


+koha   (2008-08-22 13:06:00) [22]


> Сергей М. ©   (22.08.08 13:01) [2]


SysUtils Для отладки, ну пока только используется IntTostr затем я удалю SysUtils, а некоторые его функции перетяну в отдельный модуль или заменю на API


Сергей М.   (2008-08-22 13:01:00) [23]


> на чистом API


Какой же это "чистый API" ?
Ты же SysUtils используешь, значит уже испачкался)


> Хочу опровергнуть это Делфа нихрена не хуже.


Поздравляю, ты открыл Америку)


Сергей М.   (2008-08-22 12:56:00) [24]

Конечно приводит.
И именно в приведенном коде.

Ты объект-поток создал ? Создал.
Хэндл объекта-потока получил ? Получил.
А уничтожать этот объект - закрывать полученный при создании хэндл - кто за тебя будет, Пушкин ?


Страницы:   1 2

Наверх

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