본문 바로가기
카테고리 없음

델파이 유용한 함수정리 4탄

by MonoSoft 2021. 7. 5.
728x90
반응형

델파이 유용한 함수정리 4탄

 

TTreeView에서 node마다 Hint사용하기

메인메뉴나 기타 다른용도로 TTreeView를 사용하다 보면

Node마다 Hint를 보여줘야하는 경우가 있습니다.

 

이때 프로그램에 흐름은 Hint내용을 보관할 변수가 있어야 하고

그 변수를 초기화(TTreeView에 적용)하고

Hint내용을 변경하여 보여주는 단계로 이루어집니다.

 

//선언부

PRec = ^TRec;

TRec = record

Name: string; //TTreeNode를 동적으로 생성할 때 보여주는 이름

Hint: string; //TTreeNode마다 가지는 Hint

end;

 

//초기화부분 - FromCreate나 FormShow이벤트등에 코딩하면 됩니다.

var RecPtr: PRec;

TNNode1: TTreeNode;

begin

//여기서는 1개의 노드만 설정하지만 여러개를 설정해야하는 경우는 for문등 사용하면 됩니다.

New(RecPtr);

RecPtr^.Name:= 'Node1';

RecPtr^.Hint:= 'Node1Hint';

TNNode1:= AddObject(nil, RecPtr^.Name, RecPtr);

TNNode1.StateIndex:= 1;

end;

 

//사용부분 - 마우스가 움직일때 마다 Hint에 내용을 변경합니다.

procedure TForm1.TreeView1MouseMove(Sender: TObject;

Shift: TShiftState; X, Y: Integer);

var AHit: THitTests;

begin

with TreeView1 do begin

AHit := GetHitTestInfoAt(X, Y);

if not (htNowhere in AHit) then

Hint:= PRec(GetNodeAt(X, Y).Data)^.Hint;

end;

end;

 

TTreeView에서 Directory보여주기

procedure TForm1.GetDirectories(Tree: TTreeView; Directory: string;

Item: TTreeNode; IncludeFiles: boolean);

var SearchRec: TSearchRec;

ItemTemp: TTreeNode;

begin

Tree.Items.BeginUpdate;

if Directory[length(Directory)] <> '\' then Directory := Directory + '\';

if FindFirst(Directory + '*.*', faDirectory, SearchRec) = 0 then

begin

repeat

if (SearchRec.Attr and faDirectory = faDirectory) and (SearchRec.Name[1] <> '.') then

begin

if (SearchRec.Attr and faDirectory > 0) then

Item := Tree.Items.AddChild(Item, SearchRec.Name);

ItemTemp := Item.Parent;

GetDirectories(Tree, Directory + SearchRec.Name, Item, IncludeFiles);

Item := ItemTemp;

end else

if IncludeFiles then

if SearchRec.Name[1] <> '.' then

Tree.Items.AddChild(Item, SearchRec.Name);

until FindNext(SearchRec) <> 0;

FindClose(SearchRec);

end;

Tree.Items.EndUpdate;

end;

 

procedure TForm1.Button1Click(Sender: TObject);

begin

GetDirectories(TreeView1, 'C:\', nil, True);

end;

 

Treeview에서 오른쪽마우스버튼으로 선택하기

var AHit: THitTests;

begin

with TreeViewMain do

begin

AHit := GetHitTestInfoAt(X, Y);

if not (htNowhere in AHit) then

Selected := GetNodeAt(X, Y);

end;

end;

 

TreeView에서 각 node item별로 색깔 부여하기

// 내용 : TreeView에서 각 node item별로 색깔 부여하기

// 취지 : TreeView에 경보난 시스템을 등록시킨 후 경보가 발생하면

// 해당 node의 폰트(혹은 brush) Color를 변경시켜 주고 싶어서

// 만들어 보았습니다.

// 추가 : 잘 분석해보시면 TList를 이해하는데도 도움이 될겁니다.

 

unit Unit10;

interface

uses

Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,

ComCtrls, StdCtrls, ExtCtrls;

 

type

TRectreeList = Record

NName : String[20] ;

SName : String[10] ;

end;

 

TForm1 = class(TForm)

TV: TTreeView;

Button2: TButton;

Edit1: TEdit;

Edit2: TEdit;

Button4: TButton;

procedure Button2Click(Sender: TObject);

procedure FormCreate(Sender: TObject);

procedure FormDestroy(Sender: TObject);

procedure Button4Click(Sender: TObject);

procedure TVCustomDrawItem(Sender: TCustomTreeView; Node: TTreeNode;

State: TCustomDrawState; var DefaultDraw: Boolean);

procedure FormShow(Sender: TObject);

private

{ Private declarations }

public

{ Public declarations }

procedure ChangeTreeColor(Flag:Byte; NName,SName: String);

end;

 

var

Form1: TForm1;

 

treeList : TList ;

 

implementation

 

{$R *.DFM}

 

// Item 색상을 변경

procedure TForm1.Button4Click(Sender: TObject);

begin

ChangeTreeColor(1, Edit1.Text, Edit2.Text);

end;

 

// item 색상을 원래대로...

procedure TForm1.Button2Click(Sender: TObject);

begin

ChangeTreeColor(2, Edit1.Text, Edit2.Text);

end;

 

// 등록된 값들이 저장되어 있는 값

// TList는 링크드리스트 형태로써 유용하게 사용할 수 있다.

procedure TForm1.ChangeTreeColor(Flag:Byte; NName,SName: String);

var

i : Integer ;

PTreeList : ^TRectreeList ; // TOfcs을 가리키는 포인터의 선언.

begin

case Flag of

1 : begin

// TreeList.Clear;

New(PTreeList);

PTreeList^.NName := Edit1.Text ;

PTreeList^.SName := Edit2.Text ;

TreeList.Add(PTreeList) ;

TV.Repaint ;

end;

 

2 : begin

for i := TreeList.Count-1 downto 0 do

if (Edit1.Text = TRectreeList(TreeList.Items[i]^).NName) and

(Edit2.Text = TRectreeList(TreeList.Items[i]^).SName) then

TreeList.Delete(i) ;

end;

end;

TV.Repaint ;

end;

 

// Item의 값을 비교하여 item의 Color를 변경

procedure TForm1.TVCustomDrawItem(Sender: TCustomTreeView; Node: TTreeNode;

State: TCustomDrawState; var DefaultDraw: Boolean);

var

i : Integer ;

begin

with TV.Canvas do begin

Font.Color := clBlack ; // 선택된 item의 폰트 컬러

if cdsSelected in State then

Brush.Color := clAqua ; // 선택된 item의 Brush Color

 

case Node.Level of

0 : begin

for i := 0 to treeList.Count-1 do

if (node.Text = TRectreeList(treeList.Items[i]^).NName) then begin

// Brush.Color := clFuchsia; // item의 Brush Color

Font.Color := clFuchsia; // item의 폰트 Color

break;

end;

end;

1 : begin

for i := 0 to treeList.Count-1 do

if (node.Parent.Text = TRectreeList(treeList.Items[i]^).NName) and

(node.Text = TRectreeList(treeList.Items[i]^).SName) then begin

Font.Color := clRed ; // item의 폰트 Color

break;

end;

end;

end; //case

end;

end;

 

// TreeView에 디폴트 값 등록

procedure TForm1.FormShow(Sender: TObject);

var topNode, subNode : TTreenode ;

begin

TV.Items.Clear ;

topNode := TV.TopItem ;

subNode := TV.Items.AddChild(topNode, 'aaa');

TV.items.AddChild(subNode,'박찬호');

TV.items.AddChild(subNode,'선동열');

TV.items.AddChild(subNode,'이동국');

TV.items.AddChild(subNode,'황선홍');

subNode := TV.Items.AddChild(topNode, 'bbb');

subNode := TV.Items.AddChild(topNode, 'ccc');

TV.items.AddChild(subNode,'김대중');

TV.items.AddChild(subNode,'김영삼');

TV.items.AddChild(subNode,'노태우');

TV.items.AddChild(subNode,'전두환');

subNode := TV.Items.AddChild(topNode, 'ddd');

subNode := TV.Items.AddChild(topNode, 'eee');

subNode := TV.Items.AddChild(topNode, 'fff');

 

Edit1.Text := 'ccc' ;

Edit2.Text := '전두환' ;

TV.FullExpand ;

ChangeTreeColor(1, Edit1.Text, Edit2.Text);

end;

 

procedure TForm1.FormCreate(Sender: TObject);

begin

treeList := TList.Create; // Cleate

end;

 

procedure TForm1.FormDestroy(Sender: TObject);

begin

treeList.Clear;

treeList.Free;

end;

end.

 

소켓 파일 다운로드

= 소켓을 이용한 파일 다운로드 =

procedure DownloadFile(strHost, strRemoteFileName, strLocalFileName: string;

ClientSocket: TClientSocket);

var

intReturnCode: Integer;

s: string;

szBuffer: array[0..128] of Char;

FileOut: TFileStream;

begin

if strRemoteFileName[1] <> '/' then

strRemoteFileName := '/' + strRemoteFileName;

FileOut := TFileStream.Create(strLocalFileName, fmCreate);

try

with ClientSocket do

begin

Host := strHost;

ClientType := ctBlocking;

Port := 80;

try

Open;

{send query}

s := 'GET ' + strRemoteFileName + ' HTTP/1.0'#13#10 +

'Host: ' + strHost + #13#10#13#10;

intReturnCode := Socket.SendBuf(Pointer(s)^, Length(s));

 

if intReturnCode > 0 then

begin

{receive the answer}

{ iterate until no more data }

while (intReturnCode > 0) do

begin

{ clear buffer before each iteration }

FillChar(szBuffer, SizeOf(szBuffer), 0);

{ try to receive some data }

intReturnCode := Socket.ReceiveBuf(szBuffer, SizeOf(szBuffer));

{ if received a some data, then add this data to the result string }

if intReturnCode > 0 then

FileOut.Write(szBuffer, intReturnCode);

end

end

else

MessageDlg('No answer from server', mtError, [mbOk], 0);

Close;

except

MessageDlg('No connection', mtError, [mbOk], 0);

end;

end;

finally

FileOut.Free

end;

end;

 

사용방법

procedure TForm1.Button1Click(Sender: TObject);

begin

DownloadFile('www.adfafd.co.kr'/forums.htm', 'd:\forums.htm', ClientSocket1);

end;

 

sock(indy)를 이용한 화일전송

인터넷이 보편화되면서 채팅프로그램등

여러프로그램에서 화일전송을 지원합니다.

아래 예제는 이런한 화일전송을

TIdTCPServer, TIdTCPClient콤포넌트를 사용해서 만든 예제합니다.

Server쪽은 TIdTCPServer컴포넌트한개만 사용합니다.

Client쪽은 TIdTCPClient, TEdit컴포넌트 한개씩, TButton두개를 사용합니다.

이름은 default값을 그냥 사용하고 이벤트 처리만 하면 프로그램 끝.

 

Server Event List

Form1.OnCreate:= FormCreate;

Form1.OnDestroy:= FormDestroy;

IdTCPServer1.OnExecute:= IdTCPServer1Execute;

IdTCPServer1.OnConnect:= IdTCPServer1Connect;

IdTCPServer1.OnDisConnect:= IdTCPServer1Disconnect;

 

Client Event List

Button1.OnClick:= Button1Click; <font color = blue>//접속시 사용</font>

Button2.OnClick:= Button2Click; <font color = blue>//화일전송시 사용</font>

IdTCPClient1.OnConnected:= IdTCPServer1Connect;

IdTCPClient1.OnDisconnected:= IdTCPServer1Disconnect;

 

Server 전체소스

unit Unit1;

interface

uses

Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,

StdCtrls, ExtCtrls, IdBaseComponent, IdComponent, IdTCPServer,

ComCtrls;

 

type

TForm1 = class(TForm)

IdTCPServer1: TIdTCPServer;

procedure IdTCPServer1Execute(AThread: TIdPeerThread);

procedure FormCreate(Sender: TObject);

procedure FormDestroy(Sender: TObject);

procedure IdTCPServer1Connect(AThread: TIdPeerThread);

procedure IdTCPServer1Disconnect(AThread: TIdPeerThread);

end;

 

var

Form1: TForm1;

 

implementation

 

{$R *.DFM}

 

procedure TForm1.IdTCPServer1Execute(AThread: TIdPeerThread);

var s: String;

Stream: TFileStream;

begin

s:= AThread.Connection.ReadLn;

if s='FileDown' then begin

try

Stream:= TFileStream.Create('c:\test1.jpg',fmOpenRead);

AThread.Connection.OpenWriteBuffer;

AThread.Connection.WriteStream(Stream);

AThread.Connection.CloseWriteBuffer;

Stream.Free;

AThread.Connection.Disconnect;

except

end;

end;

end;

 

procedure TForm1.FormCreate(Sender: TObject);

begin

if not IdTCPServer1.Active then IdTCPServer1.Active:= true;

end;

 

procedure TForm1.FormDestroy(Sender: TObject);

begin

IdTCPServer1.Active:= False;

end;

 

procedure TForm1.IdTCPServer1Connect(AThread: TIdPeerThread);

begin

Caption:= '클라이언트와 연결됨!';

end;

 

procedure TForm1.IdTCPServer1Disconnect(AThread: TIdPeerThread);

begin

Caption:= '클라이언트와 연결이 해제됨!';

end;

end.

 

Client 전체소스

unit Unit2;

interface

uses

Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,

IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient, ExtCtrls,

StdCtrls, ComCtrls;

 

type

TForm2 = class(TForm)

IdTCPClient1: TIdTCPClient;

Button1: TButton;

Button3: TButton;

Edit1: TEdit;

Image1: TImage;

procedure Button1Click(Sender: TObject);

procedure IdTCPClient1Connected(Sender: TObject);

procedure IdTCPClient1Disconnected(Sender: TObject);

procedure Button3Click(Sender: TObject);

end;

 

var

Form2: TForm2;

 

implementation

 

{$R *.DFM}

 

procedure TForm2.Button1Click(Sender: TObject);

begin

IdTCPClient1.Host:= Edit1.Text;

IdTCPClient1.Connect;

end;

 

procedure TForm2.IdTCPClient1Connected(Sender: TObject);

begin

Caption:= '서버와 연결됨!';

end;

 

procedure TForm2.IdTCPClient1Disconnected(Sender: TObject);

begin

Caption:= '서버와 연결이 해제됨!';

end;

 

procedure TForm2.Button3Click(Sender: TObject);

var Stream: TFileStream;

begin

Stream:= TFileStream.Create('c:\Test2.jpg',fmCreate);

with IdTCPClient1 do

try

WriteLn('FileDown');

ReadStream(Stream,-1,true);

finally

FreeAndNil(Stream);

end;

end;

end.

 

TServerSocket Control의 실행 순서

By YSU

먼저 TServerSocket의 threadblocking mode를

이해하기 위해 실행순서를 분석하므로

non-blocking부분은 제외함을 말한다.

TServerSocket의 실행 순서를 알기 전에

간단히 server의 동작 방식을 이해해야한다.

server는 무엇인가를 service하기 위해 있는거다.

service를 효율적으로 하는방식은 

꼭 computer안에만 있는건 아니다.

114안내를 보자.

전화를 걸면 맨 먼저 듣는 소리는 "안내 1234호 입니다" 다.

즉 많은 안내원중에 1234번 안내원에게

연결해 준다는 소릴게다.

그리고 안내원의"네네 안녕하십니까?"가 나오고,

내가 번호를 물으면 안내를 해주고 전화를 끋는다.

이게 server하고 똑같다.

그럼 server는 어떻게 동작하나, 먼저 client의 연결이오면

연결을 받고(accept) 그리고 대기하고 있는

service에게 연결을 전달해 준다.

 

그리고 또 기다리다 연결을 받고(accept)

또 service에게 전해주고 이걸 반복한다.

114의 "안내 1234호 입니다" 처럼.

그리고 나면 service가 그 연결을(socket) 받아

요청을 듣고, 응답을 하고, 이를 일정회 반복하고

연결을 종료한다.

그리고 114는 연중 무휴이겠지만

처음 server를 시작하는걸 Listen이라고 한다.

자그럼 TServerSocket을 보자

위의 예는 threadbloking mode의 예이다. 이 경우

TServerSocket의 TServerAcceptThread가 첫 accept를 하는 부분이고,

TServerClientThread는 service를 하는 부분이다.

server를 만드는 것은 이 service를 구현 하는 것이다.

그리고 TServerWinSocket이 첫 연결하는 전화기라면

TServerClietnWinSocket이 안내양이 사용하는 전화기다.

그럼 TServerSocket의 실행 순서를 확인해 보자.

 

1. TServerSocket의 생성

Form이 생성 될때 자동으로 호출되며,

FServerSocket := TServerWinSocket.Create;

로 TServerWinSocket을 생성한다.

 

2. TServerSocket.Active := true로 설정

TServerSocket.SetActive(true)를 호출하고,

이함수는 내부에서 FActive := true;

를 지정하고 DoActivate(true)를 호출한다.

 

DoActivate(true)는

TServerWinSocket.Listen(FHost,FAddress,FService,FPort,5)를

호출한다.

 

TServerWinSocket.Listen은

TCustomWinSocket.Listen(FHost,FAddress,FService,

FPort,5)를 호출하고, FServerAcceptThread := TServerAcceptThread.Create를

생성한다.

 

TCustomWinSocket.Listen은

FSocket := socket(PF_INET,SOCK_STREAM,IPPROTO_IP)로

실재 WinSock32를 호출하고,

InitSocket(FHost,FAddress,FService,FPort,False)에

TSockAddrIn를 구한다.

DoSetASyncStyle에서

WSAAsyncSelect(FSocket,0,0,Longint(Byte(FAsyncStyles)))와

ioctlsocket(FSocket,FIONBIO,0)를 WinSock32

함수를 호출하고 Event(Self,seListen)를 호출한다.

 

TCustomWinSocket.Event(Self,seListen)은

FOnListen(Self,Socket)에 등록된 event

handler를 출한다.

 

3. TServerAcceptThread의 Execute 실행

TServerWinSocket.Accept(FServerSocket.SocketHandle)를 계속 실행한다.

TServerWinSocket.Accept는

getsockopt(INVALID_SOCKET,SOL_SOCKET,SO_OPENTYPE,

PChar(@OldOpenType),Len)로 시작하고,

setsockopt(INVALID_SOCKET,SOL_SOCKET,

SO_OPENTYPE,PChar(@OldOpenType),Len)로 끝낸다

즉 OpenType을 보관해 놓았다가

다시 되 돌린다.

그 사이에서는 setsockopt(INVALID_SOCKET,SOL_SOCKET,

SO_OPENTYPE,PChar(@SO_SYNCHRONOUS_NONALERT),Len)로

setting을 변경하고,

ClientWinSocket := WinSock.accept(Socket, @Addr, @Len)인 WinSock32함수를

호출해 실재 connection을 기다리게 된다.

그리고 ClientSocket :=GetClientSocket(ClientWinSocket)을

호출해 TServerClientWinSocket을 얻고

FOnSocketEvent(Self, ClientSocket, seAccept)로

지정된 event handler를 호출하고

ClientSocket.ASyncStyles := []를 지정하고 GetServerThread(ClientSocket)

로 TServerClinetThread를 얻는다.

 

GetClientSocket은 FOnGetSocket(Self,Socket,Result)로 지정된 event handler로

TServerClinetWinSocket을 얻을려고 시도해보고,

안되면 TServerClientWinSocket.Create(Socket, Self)로 직접 생성한다.

 

GetServerThread는 먼저 FActiveThreads에서 ClientSocket = nil인 즉 현재

service를 않하는 TServerClientThread를 얻어보고, 만일 있으면

TServerClientThread.ReActivate(ClientSocket)를 호출한다.

만일 현재 노는게 없으면 FOnGetThread(Self,ClientSocket,Result)로

지정된 event handler를 호출해서 얻도록하고 안되면,

DoCreateThread(ClientSocket)로 직접 생성한다.

 

DoCreateThread은 TServerClientThread.Create를 호출해 생성하고,

TServerClientThread.Create내에서 ReActivate(ASocket)을 호출한다.

즉 어떻게한던 TServerClientThread.ReActivate(ClientSocket)은 항상 호출 된다.

 

ReActivate은 TServerClientWinSocket과 TServerWinSocket를 저장하고

TServerWinSocket.AddThread(Self)로 자신을 등록하고,

TServerClientWinSocket.OnSocketEvent := HandleEvent과

TServerClientWinSocket.OnErrorEvent := HandleError의

event handler를 연결한다.

 

마지막으로 Windows.SetEvent(Handle)를 호출한다.

4. TServerClientThread의 Execute 실행

TServerWinSocket.ThreadStart(Self)로

FOnThreadStart(Self,AThread)인 등록된

event handle을 맨 먼제 호출하고,

TServerWinSocket.ThreadEnd(Self)로

FOnThreadEnd(Self, AThread)인 등록된

event handler를 마지막으로 호출한다.

그리고 IF StartConnect THEN ClientExecute;

IF EndConnect THEN Break;

를 무한 반복한다.

 

StartConnect는 WaitForSingleObject(Handle,INFINITE)로 기다리다.

terminated를 확인하여 terminate가 않됬으면 true를 돌려준다.

EndConnect는 terminate이고 KeepInCache가 아니면 true를 돌려준다.

 

ClientExecute는 IF select(0, @FDSet, nil, nil, @TimeVal) > 0로 읽을게 있으면

TServerClientWinSocket.ReceiveBuf(FDSet, -1)를 읽어봐 읽어지면

Synchronize(DoRead)로 TServerWinSocket.ClinetEvent(seRead)를 호출하고

ClinetRead를 거처 FOnClinetRead에 등록된 event handler를 호출한다.

 

그리고 IF select(0, nil, @FDSet, nil, @TimeVal) > 0로 읽을게 있으면

TServerClientWinSocket.ReceiveBuf(FDSet, -1)를 읽어봐 쓸게있으면

Synchronize(DoWrite)로 TServerWinSocket.ClinetEvent(seWrite)를 호출하고

ClinetWrite를 거처 FOnClinetWrite에 등록된 event handler를 호출한다.

 

5. Window가 message를 보내오는 경우

TServerClientWinSocket.OnSocketEvent

TServerClientThread.HandleEvent(Sender, Socket, SocketEvent)

Event(SocketEvent)

TServerWinSocket.ClientEvent(Self, ClientSocket, SocketEvent)

ClientConnect(Socket)

OR ClientDisconnect(Socket)

OR ClientRead(Socket)

OR ClientWrite(Socket)

FOnClientConnect(Socket)

OR FOnClientDisconnect(Socket)

OR FOnClientRead(Socket)

OR FOnClientWrite(Socket)에 등록된 event handler를 호출한다.

 

TServerClientWinSocket.OnErrorEvent

TServerClientThread.HandleError(Sender,Socket,ErrorEvent,ErrorCode)

Error(ErrorEvent, ErrorCode)

TServerWinSocket.ClientError(Sender,Socket,ErrorEvent,ErrorCode)

ClinetErrorEvent(Socket, ErrorEvent, ErrorCode)

FOnClinetError(Socket, ErrorEvent, ErrorCode)

에 등록된 event handler를 호출한다.

 

6. 참고

indent는 호출되어지는 순서를 나타낸다.

TServerSocket.Create

FServerSocket := TServerWinSocket.Create;

TServerSocket.Active := true;

TServerSocket.SetActive(true);

FActive := true;

DoActivate(true);

TServerWinSocket.Listen(FHost, FAddress, FService, FPort, 5);

TCustomWinSocket.Listen(FHost, FAddress, FService, FPort, 5);

FSocket := socket(PF_INET, SOCK_STREAM, IPPROTO_IP);

SockAddrIn := InitSocket(FHost, FAddress, FService, FPort, False);

TSockAddrIn.sin_family := PF_INET;

TSockAddrIn.sin_addr := {LookupName(FHost)

OR inet_addr(PChar(FAddress))

OR INADDR_ANY

};

 

TSockAddrIn.sin_port := {htons(LookupService(FService))

OR htons(FPort)

};

 

DoSetASyncStyles;

IF AsyncStyles

WSAAsyncSelect(FSocket, CM_SOCKETMESSAGE, Handle,

Longint(Byte(FAsyncStyles)));

ELSE

WSAAsyncSelect(FSocket, 0, 0, Longint(Byte(FAsyncStyles)));

ioctlsocket(FSocket, FIONBIO, 0);

Event(Self, seListen);

FOnListen(Self, Socket);

FServerAcceptThread := TServerAcceptThread.Create(False, Self);

TThread.Create(False);

....

TServerAcceptThread.Execute;

TServerWinSocket.Accept(FServerSocket.SocketHandle);

getsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE,

PChar(@OldOpenType),Len);

IF stThreadBlocking

setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE,

PChar(@SO_SYNCHRONOUS_NONALERT), Len);

ClientWinSocket := WinSock.accept(Socket, @Addr, @Len);

ClientSocket := GetClientSocket(ClientWinSocket);

{FOnGetSocket(Self, Socket, Result)

OR TServerClientWinSocket.Create(Socket, Self)

};

FOnSocketEvent(Self, ClientSocket, seAccept);

IF stThreadBlocking

ClientSocket.ASyncStyles := [];

GetServerThread(ClientSocket);

{SELECT TServerClientThread

FROM FActiveThreads

WHERE ClientSocket = nil

TServerClientThread.ReActivate(ClientSocket);

TServerClientWinSocket := ASocket;

TServerWinSocket := FClientSocket.ServerWinSocket;

TServerWinSocket.AddThread(Self);

FActiveThreads.Add(Self);

TServerClientWinSocket.OnSocketEvent := HandleEvent;

TServerClientWinSocket.OnErrorEvent := HandleError;

FEvent.SetEvent;

Windows.SetEvent(Handle);

OR FOnGetThread(Self, ClientSocket, Result)

OR DoCreateThread(ClientSocket)

TServerClientThread.Create(False, ClientSocket);

ReActivate(ASocket); <- 상동

};

setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE,

PChar(@OldOpenType), Len);

...

TServerClientThread.Execute;

TServerWinSocket.ThreadStart(Self);

FOnThreadStart(Self, AThread);

WHILE

IF StartConnect

WaitForSingleObject(Handle, INFINITE)

RETURN NOT terminated

ClientExecute;

FD_ZERO(FDSet);

FD_SET(TServerClientWinSocket.SocketHandle, FDSet);

TimeVal.tv_sec := 0;

TimeVal.tv_usec := 500;

IF select(0, @FDSet, nil, nil, @TimeVal) > 0

IF TServerClientWinSocket.ReceiveBuf(FDSet, -1) = 0

Break

ELSE

Synchronize(DoRead);

TServerWinSocket.ClinetEvent(seRead);

ClinetRead

FOnClinetRead

IF select(0, nil, @FDSet, nil, @TimeVal) > 0

Synchronize(DoWrite);

TServerWinSocket.ClinetEvent(seWrite);

ClinetWrite

FOnClinetWrite

IF EndConnect

RETURN terminated AND NOT KeepInCache

Break;

TServerWinSocket.ThreadEnd(Self);

FOnThreadEnd(Self, AThread);

...

TServerClientWinSocket.OnSocketEvent;

TServerClientThread.HandleEvent(Sender, Socket, SocketEvent);

Event(SocketEvent);

TServerWinSocket.ClientEvent(Self, ClientSocket, SocketEvent);

{ClientConnect(Socket)

OR ClientDisconnect(Socket)

OR ClientRead(Socket)

OR ClientWrite(Socket)

};

{FOnClientConnect(Socket)

OR FOnClientDisconnect(Socket)

OR FOnClientRead(Socket)

OR FOnClientWrite(Socket)

};

...

TServerClientWinSocket.OnErrorEvent;

TServerClientThread.HandleError(Sender,Socket,ErrorEvent,ErrorCode);

Error(ErrorEvent, ErrorCode);

TServerWinSocket.ClientError(Sender,Socket,ErrorEvent,ErrorCode);

ClinetErrorEvent(Socket, ErrorEvent, ErrorCode);

FOnClinetError(Socket, ErrorEvent, ErrorCode);

728x90
반응형

댓글