📄 wsocket.pas
字号:
multicast code: listening on a specific interface was ignored.
He fixed Listen and Connect.
About multithreading and event-driven:
TWSocket is a pure asynchronous component. It is non-blocking and
event-driven. It means that when you request an operation such as connect,
the component start the operation your requested and give control back
immediately while performing the operation in the background automatically.
When the operation is done, an event is triggered (such as
OnSessionConnected if you called Connect).
This asynchronous non-blocking behaviour is very high performance but a
little bit difficult to start with. For example, you can't call Connect and
immediately call SendStr the line below. If you try, you'll have an
exception triggered saying you are not connected. Calling connect will start
connection process but will return long before connection is established.
Calling SendStr at the next line will not work because the socket is not
connected yet. To make it works the right way, you have to put your SendStr
in the OnSessionConnected event.
The asynchronous operation allows you to do several TCP/IP I/O
simultaneously. Just use as many component as you need. Each one will
operate independently of the other without blocking each other ! So you
basically don't need multi-threading with TWSocket, unless YOUR processing
is lengthy and blocking.
If you have to use multithreading, you have two possibilities:
1) Create your TWSocket from your thread's Execute method
2) Attach a TWSocket to a given thread using ThreadAttach.
In both cases, you must set MultiThreaded property to TRUE.
If you don't use one of those methods, you'll end up with a false
multithreaded program: all events will be processed by the main tread !
For both methods to work, you MUST have a message loop withing your thread.
Delphi create a message loop automatically for the main thread (it's in
the Forms unit), but does NOT create one in a thread ! For your convenience,
TWSocket has his own MessageLoop procedure. You can use it from your thread.
Sample program MtSrv uses first method while ThrdSrv uses second method.
Sample program TcpSrv is much the same as ThrdSrv but doesn't use any
thread. You'll see that it is able to server a lot of simultaneous clients
as well and it is much simpler.
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
unit WSocket;
{$B-} { Enable partial boolean evaluation }
{$T-} { Untyped pointers }
{$X+} { Enable extended syntax }
{ VER80 => Delphi 1 }
{ VER90 => Delphi 2 }
{ VER93 => Bcb 1 }
{ VER100 => Delphi 3 }
{ VER110 => Bcb 3 }
{ VER120 => Delphi 4 }
{ VER125 => Bcb 4 }
{ VER130 => Delphi 5 }
{ VER135 => Bcb 5 }
{ VER140 => Delphi 6 }
{$IFNDEF VER80} { Not for Delphi 1 }
{$H+} { Use long strings }
{$J+} { Allow typed constant to be modified }
{$ENDIF}
{$IFDEF VER110} { C++ Builder V3.0 }
{$ObjExportAll On}
{$ENDIF}
{$IFDEF VER125} { C++ Builder V4.0 }
{$ObjExportAll On}
{$ENDIF}
interface
uses
WinTypes, WinProcs, Messages, Classes, SysUtils,
{$IFNDEF NOFORMS} { See comments in history at 14/02/99 }
Forms,
{$ENDIF}
WSockBuf, WinSock;
const
WSocketVersion = 447;
CopyRight : String = ' TWSocket (c) 1996-2002 Francois Piette V4.47 ';
WM_ASYNCSELECT = WM_USER + 1;
WM_ASYNCGETHOSTBYNAME = WM_USER + 2;
WM_ASYNCGETHOSTBYADDR = WM_USER + 3;
WM_CLOSE_DELAYED = WM_USER + 4;
WM_WSOCKET_RELEASE = WM_USER + 5;
WM_TRIGGER_EXCEPTION = WM_USER + 6;
WM_TRIGGER_DATA_AVAILABLE = WM_USER + 20;
WSA_WSOCKET_TIMEOUT = 12001;
{$IFDEF WIN32}
winsocket = 'wsock32.dll'; { 32 bits TCP/IP system DLL }
{$ELSE}
winsocket = 'winsock.dll'; { 16 bits TCP/IP system DLL }
{$ENDIF}
type
TWndMethod = procedure(var Message: TMessage) of object;
ESocketException = class(Exception);
TBgExceptionEvent = procedure (Sender : TObject;
E : Exception;
var CanClose : Boolean) of object;
TSocketState = (wsInvalidState,
wsOpened, wsBound,
wsConnecting, wsConnected,
wsAccepting, wsListening,
wsClosed);
TSocketSendFlags = (wsSendNormal, wsSendUrgent);
TSocketLingerOnOff = (wsLingerOff, wsLingerOn, wsLingerNoSet);
TSockAddr = Winsock.TSockAddr;
TDataAvailable = procedure (Sender: TObject; Error: word) of object;
TDataSent = procedure (Sender: TObject; Error: word) of object;
TSendData = procedure (Sender: TObject; BytesSent: Integer) of object;
TSessionClosed = procedure (Sender: TObject; Error: word) of object;
TSessionAvailable = procedure (Sender: TObject; Error: word) of object;
TSessionConnected = procedure (Sender: TObject; Error: word) of object;
TDnsLookupDone = procedure (Sender: TObject; Error: Word) of object;
TChangeState = procedure (Sender: TObject;
OldState, NewState : TSocketState) of object;
TDebugDisplay = procedure (Sender: TObject; var Msg : String) of object;
TWSocketSyncNextProc = procedure of object;
TWSocketOption = (wsoNoReceiveLoop, wsoTcpNoDelay);
TWSocketOptions = set of TWSocketOption;
{ TSocket type is defined for Delphi 1/2/3 but not for all others }
{$IFNDEF VER80} { Delphi 1 }
{$IFNDEF VER90} { Delphi 2 }
{$IFNDEF VER100} { Delphi 3 }
TSocket = u_int;
{$ENDIF}
{$ENDIF}
{$ENDIF}
TCustomWSocket = class(TComponent)
private
FDnsResult : String;
FDnsResultList : TStrings;
FASocket : TSocket; { Accepted socket }
FBufList : TList;
FBufSize : Integer;
FSendFlags : Integer;
FLastError : Integer;
FWindowHandle : HWND;
FDnsLookupBuffer : array [0..MAXGETHOSTSTRUCT] of char;
FDnsLookupHandle : THandle;
FDnsLookupCheckMsg : Boolean;
FDnsLookupTempMsg : TMessage;
{$IFDEF VER80}
FTrumpetCompability : Boolean;
{$ENDIF}
protected
FHSocket : TSocket;
FAddrStr : String;
FAddrResolved : Boolean;
FAddrFormat : Integer;
FAddrAssigned : Boolean;
FProto : integer;
FProtoAssigned : Boolean;
FProtoResolved : Boolean;
FLocalPortResolved : Boolean;
FProtoStr : String;
FPortStr : String;
FPortAssigned : Boolean;
FPortResolved : Boolean;
FPortNum : Integer;
FLocalPortStr : String;
FLocalPortNum : Integer;
FLocalAddr : String; { IP address for local interface to use }
FType : integer;
FLingerOnOff : TSocketLingerOnOff;
FLingerTimeout : Integer; { In seconds, 0 = disabled }
ReadLineCount : Integer;
{bWrite : Boolean;23/12/01}
{nMoreCnt : Integer;23/12/01}
{bMoreFlag : Boolean; 23/12/01}
{nMoreMax : Integer;23/12/01}
bAllSent : Boolean;
FReadCount : LongInt;
FPaused : Boolean;
FCloseInvoked : Boolean;
FFlushTimeout : Integer;
FMultiThreaded : Boolean;
FMultiCast : Boolean;
FMultiCastAddrStr : String;
FMultiCastIpTTL : Integer;
FReuseAddr : Boolean;
FComponentOptions : TWSocketOptions;
FState : TSocketState;
FRcvdFlag : Boolean;
FTerminated : Boolean;
FSelectEvent : LongInt;
FOnSessionAvailable : TSessionAvailable;
FOnSessionConnected : TSessionConnected;
FOnSessionClosed : TSessionClosed;
FOnChangeState : TChangeState;
FOnDataAvailable : TDataAvailable;
FOnDataSent : TDataSent;
FOnSendData : TSendData;
{ FOnLineTooLong : TNotifyEvent; }
FOnDnsLookupDone : TDnsLookupDone;
FOnError : TNotifyEvent;
FOnBgException : TBgExceptionEvent;
FOnDisplay : TDebugDisplay;
FOnMessagePump : TNotifyEvent;
FThreadId : THandle;
procedure WndProc(var MsgRec: TMessage); virtual;
procedure AllocateSocketHWnd; virtual;
procedure DeallocateSocketHWnd; virtual;
procedure SocketError(sockfunc: string);
procedure WMASyncSelect(var msg: TMessage); message WM_ASYNCSELECT;
procedure WMAsyncGetHostByName(var msg: TMessage); message WM_ASYNCGETHOSTBYNAME;
procedure WMAsyncGetHostByAddr(var msg: TMessage); message WM_ASYNCGETHOSTBYADDR;
procedure WMCloseDelayed(var msg: TMessage); message WM_CLOSE_DELAYED;
procedure WMRelease(var msg: TMessage); message WM_WSOCKET_RELEASE;
procedure ChangeState(NewState : TSocketState);
procedure TryToSend;
procedure ASyncReceive(Error : Word; MySocketOptions : TWSocketOptions);
procedure AssignDefaultValue; virtual;
procedure InternalClose(bShut : Boolean; Error : Word); virtual;
procedure Notification(AComponent: TComponent; operation: TOperation); override;
procedure SetSendFlags(newValue : TSocketSendFlags);
function GetSendFlags : TSocketSendFlags;
procedure SetAddr(InAddr : String);
function GetAddr : String;
procedure SetRemotePort(sPort : String); virtual;
function GetRemotePort : String;
procedure SetLocalAddr(sLocalAddr : String);
procedure SetLocalPort(sLocalPort : String);
procedure SetProto(sProto : String); virtual;
function GetProto : String;
function GetRcvdCount : LongInt; virtual;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -