📄 psisockethandle.pas
字号:
unit PsiSocketHandle;
//******************************************************************************
// The original software is under
// Copyright (c) 1993 - 2000, Chad Z. Hower (Kudzu)
// and the Indy Pit Crew - http://www.nevrona.com/Indy/
//
// Amended : November 2000, by Michael M. Michalak MACS for use with
// MorphTek.com Inc Peer to Peer Open Source Components - http://www.morphtek.com
//
//******************************************************************************
interface
uses
Classes,
PsiGlobal,
PsiStack, PsiStackConsts;
type
TPsiSocketHandle = class;
TPsiSocketHandles = class(TOwnedCollection)
protected
FDefaultPort: integer;
//
function GetItem(Index: Integer): TPsiSocketHandle;
procedure SetItem(Index: Integer; const Value: TPsiSocketHandle);
public
constructor Create(AOwner: TComponent); reintroduce;
function add: TPsiSocketHandle; reintroduce;
property Items[Index: Integer]: TPsiSocketHandle read GetItem write SetItem; default;
//
property DefaultPort: integer read FDefaultPort write FDefaultPort;
end;
TPsiSocketHandle = class(TCollectionItem)
protected
FHandle: TPsiStackSocketHandle;
FHandleAllocated: Boolean;
FIP, FPeerIP: string;
FPort, FPeerPort: integer;
public
procedure Accept(ASocket: TPsiStackSocketHandle; var VIP: string; var VPort: Integer);
procedure AllocateSocket(const ASocketType: Integer = Psi_SOCK_STREAM;
const AProtocol: Integer = Psi_IPPROTO_IP);
// Returns True if error was ignored (Matches iIgnore), false if no error occurred
procedure Assign(Source: TPersistent); override;
procedure Bind;
procedure CloseSocket; virtual;
function Connect(const AFamily: Integer = Psi_PF_INET): Integer; virtual;
constructor Create(ACollection: TCollection); override;
destructor Destroy; override;
procedure Listen(const anQueueCount: integer = 5);
function Readable(AMSec: Integer = PsiTimeoutDefault): boolean;
function Recv(var ABuf; ALen, AFlags: Integer): Integer;
function RecvFrom(var ABuffer; const ALength, AFlags: Integer; var VIP: string;
var VPort: Integer): Integer; virtual;
function Send(var Buf; len, flags: Integer): Integer;
procedure SendTo(const AIP: string; const APort: Integer; var ABuffer;
const ABufferSize: Integer);
procedure SetPeer(const asIP: string; anPort: integer);
function SetSockOpt(level, optname: Integer; optval: PChar; optlen: Integer): Integer;
//
property HandleAllocated: Boolean read FHandleAllocated;
property Handle: TPsiStackSocketHandle read FHandle;
property PeerIP: string read FPeerIP;
property PeerPort: integer read FPeerPort;
published
property IP: string read FIP write FIP;
property Port: integer read FPort write FPort;
end;
implementation
uses
PsiAntiFreezeBase,
PsiComponent, PsiException,
PsiResourceStrings;
{ TPsiSocketHandle }
procedure TPsiSocketHandle.AllocateSocket(const ASocketType: Integer = Psi_SOCK_STREAM;
const AProtocol: Integer = Psi_IPPROTO_IP);
begin
// If we are reallocating a socket - close and destroy the old socket handle
CloseSocket;
FHandle := GStack.CreateSocketHandle(ASocketType, AProtocol);
FHandleAllocated := True;
end;
procedure TPsiSocketHandle.CloseSocket;
begin
if HandleAllocated then begin
// Must be first, closing socket will trigger some errors, and they
// may then check (in other threads) Connected, which checks this.
FHandleAllocated := False;
GStack.WSCloseSocket(Handle);
FHandle := Psi_INVALID_SOCKET;
end;
end;
function TPsiSocketHandle.Connect(const AFamily: Integer = Psi_PF_INET): Integer;
begin
result := GStack.WSConnect(Handle, AFamily, IP, Port);
end;
destructor TPsiSocketHandle.Destroy;
begin
CloseSocket;
inherited;
end;
function TPsiSocketHandle.Recv(var ABuf; ALen, AFlags: Integer): Integer;
begin
result := GStack.WSRecv(Handle, ABuf, ALen, AFlags);
end;
function TPsiSocketHandle.Send(var Buf; len, flags: Integer): Integer;
begin
result := GStack.WSSend(Handle, Buf, len, flags);
end;
function TPsiSocketHandle.SetSockOpt(level, optname: Integer; optval: PChar;
optlen: Integer): Integer;
begin
result := GStack.WSSetSockOpt(Handle, level, optname, optval, optlen);
end;
procedure TPsiSocketHandle.SendTo(const AIP: string; const APort: Integer; var ABuffer;
const ABufferSize: Integer);
var
BytesOut: Integer;
begin
BytesOut := GStack.WSSendTo(Handle, ABuffer, ABufferSize, 0, AIP, APort);
if BytesOut = 0 then begin
raise EPsiException.Create(RS0BytesWereSent);
end else if BytesOut = Psi_SOCKET_ERROR then begin
if GStack.WSGetLastError() = Psi_WSAEMSGSIZE then begin
raise EPsiException.Create(RSPackageSizeTooBig);
end else begin
GStack.CheckForSocketError;
end;
end else if BytesOut <> ABufferSize then begin
raise EPsiException.Create(RSNotAllBytesSent);
end;
end;
function TPsiSocketHandle.RecvFrom(var ABuffer; const ALength, AFlags: Integer; var VIP: string;
var VPort: Integer): Integer;
begin
result := GStack.WSRecvFrom(Handle, ABuffer, ALength, AFlags, VIP, VPort);
end;
procedure TPsiSocketHandle.Bind;
begin
if GStack.CheckForSocketError(GStack.WSBind(Handle, Psi_PF_INET, IP, Port), [Psi_WSAEADDRINUSE])
then begin
raise EPsiException.Create(RSCouldNotBindSocket);
end;
end;
procedure TPsiSocketHandle.SetPeer(const asIP: string; anPort: integer);
begin
FPeerIP := asIP;
FPeerPort := anPort;
end;
procedure TPsiSocketHandle.Listen(const anQueueCount: integer);
begin
GStack.CheckForSocketError(GStack.WSListen(Handle, anQueueCount));
end;
procedure TPsiSocketHandle.Accept(ASocket: TPsiStackSocketHandle; var VIP: string;
var VPort: Integer);
var
AcceptedSocket: TPsiStackSocketHandle;
begin
AcceptedSocket := GStack.WSAccept(ASocket, VIP, VPort);
GStack.CheckForSocketError(AcceptedSocket);
FHandle := AcceptedSocket;
FHandleAllocated := True;
end;
constructor TPsiSocketHandle.Create(ACollection: TCollection);
begin
inherited;
if assigned(ACollection) then begin
Port := TPsiSocketHandles(ACollection).DefaultPort;
end;
end;
function TPsiSocketHandle.Readable(AMSec: Integer): boolean;
var
ReadList: TList;
begin
if not FHandleAllocated then begin
raise EPsiConnClosedGraceful.Create(RSConnectionClosedGracefully);
end;
if GAntiFreeze <> nil then begin
if GAntiFreeze.Active then begin
if AMSec = PsiTimeoutInfinite then begin
repeat
result := Readable(GAntiFreeze.IdleTimeOut);
until result;
exit;
end else if AMSec > GAntiFreeze.IdleTimeOut then begin
result := Readable(AMSec - GAntiFreeze.IdleTimeOut);
if result then begin
exit;
end else begin
AMSec := GAntiFreeze.IdleTimeOut;
end;
end;
end;
end;
ReadList := TList.Create; try
ReadList.Add(Pointer(Handle));
Result := GStack.WSSelect(ReadList, nil, nil, AMSec) = 1;
TPsiAntiFreezeBase.DoProcess(result = false);
finally ReadList.free; end;
end;
procedure TPsiSocketHandle.Assign(Source: TPersistent);
var hdl : TPsiSocketHandle;
begin
if ClassType <> Source.ClassType then
begin
Inherited
end
else
begin
hdl := TPsiSocketHandle(Source);
IP := hdl.IP;
Port := hdl.Port;
end;
end;
{ TPsiSocketHandles }
function TPsiSocketHandles.add: TPsiSocketHandle;
begin
result := Inherited add as TPsiSocketHandle;
result.Port := DefaultPort;
end;
constructor TPsiSocketHandles.Create(AOwner: TComponent);
begin
inherited Create(AOwner, TPsiSocketHandle);
end;
function TPsiSocketHandles.GetItem(Index: Integer): TPsiSocketHandle;
begin
result := TPsiSocketHandle(inherited Items[index]);
end;
procedure TPsiSocketHandles.SetItem(Index: Integer; const Value: TPsiSocketHandle);
begin
inherited SetItem(Index, Value);
end;
end.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -