델파이 유용한 함수정리 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);
댓글