📄 unasockets.pas
字号:
(*
----------------------------------------------
unaSockets.pas
Windows sockets wrapper classes
----------------------------------------------
This source code cannot be used without
proper license granted to you as a private
person or an entity by the Lake of Soft, Ltd
Visit http://lakeofsoft.com/ for more information.
Copyright (c) 2001, 2007 Lake of Soft, Ltd
All rights reserved
----------------------------------------------
created by:
Lake, ?? 2001
modified by:
Lake, Jan-Dec 2002
Lake, Jan-Oct 2003
Lake, Jan-Dec 2004
Lake, Jan-Sep 2005
Lake, Feb-Dec 2006
Lake, Apr 2007
----------------------------------------------
*)
{$I unaDef.inc}
{$IFDEF DEBUG }
{xx $DEFINE LOG_RAW_DATA_PACKETS } // define to log data packets received over network
{$DEFINE LOG_SOCKS_THREADS } // define to log data packets received over network
{$ENDIF }
unit
unaSockets;
interface
{DP:UNIT
Contains Windows sockets version 1.1 implementation.
}
uses
Windows, unaTypes, WinSock, unaClasses
{$IFDEF __SYSUTILS_H_ }
, Math
{$ENDIF}
;
const
{$IFDEF __BEFORE_D6__ }
{$EXTERNALSYM SD_BOTH }
SD_BOTH = 2;
{$ENDIF}
{$EXTERNALSYM SO_MAX_MSG_SIZE }
SO_MAX_MSG_SIZE = $2003; // maximum message size
//
c_maxThreadPoolSize = 256; // maximum size of threads pool
//
c_defUdpConnTimeout = 60000 * 3; // default timeout for sockets "connected" to UDP server
type
//
// -- unaWSA --
//
{DP:CLASS
Windows sockets manager class.
}
unaWSA = class(unaObject)
private
f_data: tWSAData;
f_status: int;
f_gate: unaInProcessGate;
public
{DP:METHOD
Creates and initializes internal structures. If active = true startups the Windows Sockets.
}
constructor create(active: bool = true; version: unsigned = $0101);
destructor Destroy(); override;
//
{DP:METHOD
Startups the Windows sockets.
}
function startup(version: unsigned = $0101): int;
{DP:METHOD
Cleanups the Windows sockets.
}
function shutdown(): int;
function getStatus(): int; // 0 - ok
// WSASYSNOTREADY, WSAVERNOTSUPPORTED
// WSAEINPROGRESS, WSAEPROCLIM, WSAEFAULT
{DP:METHOD
Returns true if Windows sockets were started up successfully.
}
function isActive(): bool;
end;
//
// -- unaSocket --
//
unaSocketEvent = (
// server
unaseServerListen,
unaseServerStop,
unaseServerConnect,
unaseServerData,
unaseServerDisconnect,
// client
unaseClientConnect,
unaseClientData,
unaseClientDisconnect,
// thread
unaseThreadStartupError
);
{DP:CLASS
Base class implementing Windows socket.
}
unaSocket = class(unaObject)
private
f_socket: tSocket;
f_socketAddressFamily: int;
f_socketProtocol: int;
f_socketType: int;
f_host: string;
//
f_bindToIP: string;
f_bindToPort: protoEnt;
//
f_port: protoEnt;
//
function socket(): int;
function check_error(timeout: unsigned = 0): bool;
function check_read(timeout: unsigned = 0): bool;
function check_write(timeout: unsigned = 0): bool;
//
function getIsActive(): bool;
function getBufSize(index: Integer): unsigned;
procedure setBufSize(index: Integer; value: unsigned);
//
procedure setBindToPort(const value: string);
function getBindToPort: string;
protected
{DP:METHOD
returns 0 if ok (or not connected/active), or specific WSA error
}
function closeSocket(): int; virtual;
//
function bind(addr: pSockAddrIn = nil): int; virtual;
{DP:METHOD
select() returns 0 if timeout, 1 if ok, or some specific WSA error.
Timeout specifies the amount of time in milliseconds.
}
function select(r, w, e: pbool; timeout: unsigned = Windows.INFINITE): int; virtual;
//
function ioctl(command: unsigned; var param: int): int; virtual;
public
{DP:METHOD
Initializes the socket.
}
constructor create();
{DP:METHOD
Closes and destroys the socket.
}
destructor Destroy(); override;
{DP:METHOD
Returns socket handle.
}
function getSocket(forceCreate: bool = false): tSocket;
{DP:METHOD
Returns sockaddr_in structure filled with address:port values which corresponds to the socket.
}
function getSockAddr(var addr: sockaddr_in): int;
//
{DP:METHOD
Binds the socket to specified (or auto-assigned port) number and starts listening for incoming connections.
<BR />Returns true if socket is already in listening mode.
}
function listen(backlog: int = SOMAXCONN): int;
{DP:METHOD
Connects the socket to remote host.
<BR>Returns:
<UL>
<LI>0 - socket has been connected successfully</LI>
<LI>or specific WSA error (which is not zero)</LI>
</UL>
}
function connect(addr: pSockAddrIn = nil): int;
{DP:METHOD
Closes the socket. If graceful = true, socket will gracefully close all operations, and then disconnect.
<BR />Returns 0 if no error occurred (or socket was not connected/listening), or specific WSA error (which is not zero).
}
function close(graceful: bool = true): int;
{DP:METHOD
Blocks until new connection will be established with socket, or timeout value expires.
<BR />Returns new connected client socket, or nil if timeout or error occur.
<BR /><STRONG>NOTE</STRONG>: this method should be used with TCP sockets only.
}
function accept(out socket: tSocket; timeout: unsigned = Windows.INFINITE): unaSocket;
{DP:METHOD
Closes the open socket. how can have the following values:
<UL>
<LI>SD_RECEIVE - complete and disable receiving operations</LI>
<LI>SD_SEND - complete and disable sending operations</LI>
<LI>SD_BOTH - complete and disable both operations</LI>
</UL>
<BR />Returns 0 if no error occurred, or specific WSA error.
<BR /><STRONG>NOTE</STRONG>: do not try to reuse the socket after it has been successfully shut down.
Call close() to clean up the socket before reusing it again.
}
function shutdown(how: int): int;
{DP:METHOD
Returns true, if socket is connected to remote host, and there was no error.
}
function isConnected(timeout: unsigned = 0): bool;
{DP:METHOD
Returns true, if socket is listening, and there was no error
}
function isListening(): bool;
{DP:METHOD
Returns True if there are some chances data could be sent now.
}
function okToRead(timeout: unsigned = 0; noCheckState: bool = false): bool;
{DP:METHOD
Returns True if there are some chances data could be sent now.
}
function okToWrite(timeout: unsigned = 0; noCheckState: bool = false): bool;
//
{DP:METHOD
Returns -1, if socket is not connected or no data were available within timeout period.
<BR />Returns 0, if data was read, and size specifies actual amount of data read.
<BR />Otherwise returns specific WSA error.
}
function read(const buf: pointer; var size: unsigned; timeout: unsigned = Windows.INFINITE; noCheck: bool = false): int;
{DP:METHOD
Reads a string from socket.
}
function readString(noCheck: bool = false): string;
{DP:METHOD
Waits until data will be available to read from socket or timeout expire.
}
function waitForData(timeout: unsigned = Windows.INFINITE; noCheckState: bool = false): bool;
{DP:METHOD
Returns number of bytes available to read from socket.
}
function getPendingDataSize(noCheckState: bool = false): unsigned;
{DP:METHOD
Sends data into socket.
<BR />Returns 0 or specific WSA error.
}
function send(buf: pointer; size: unsigned; noCheck: bool = false): int; overload;
{DP:METHOD
Sends a string into socket.
<BR />Returns 0 or specific WSA error.
}
function send(const value: string; noCheck: bool = false): int; overload;
//
{DP:METHOD
Returns boolean option of the socket.
}
function getOptBool(opt: int): bool;
{DP:METHOD
Returns integer option of the socket.
}
function getOptInt(opt: int): int;
{DP:METHOD
Sets boolean option of the socket.
}
function setOptBool(opt: int; value: bool): int;
{DP:METHOD
Sets integer option of the socket.
}
function setOptInt(opt: int; value: int): int;
{DP:METHOD
Sets remote host address/DNS name. Does nothing if socket is active (connected/listening).
}
procedure setHost(const host: string);
{DP:METHOD
Sets remote port number for the socket. This value will be used to connect socket to.
}
function setPort(const port: string): bool; overload;
{DP:METHOD
Sets remote port number for the socket. This value will be used to connect socket to.
}
function setPort(port: word): bool; overload;
{DP:METHOD
Returns remote port value as string.
}
function getPort(): string;
{DP:METHOD
Returns remote port value as word.
}
function getPortInt(): word;
{DP:METHOD
Returns maximum transmission unit (MTU) size.
<BR /><STRONG>NOTE</STRONG>: this value should not be used as real MTU size, but only as an estimation for most cases.
}
class function getGeneralMTU(): unsigned;
{DP:METHOD
Returns maximum transmission unit (MTU) size for connected socket.
}
function getMTU(): uint;
{DP:METHOD
Binds the socket to specified port.
If port value is -1 (default), this function uses the bindToPort property as a port number to bind to.
If port value is 0, this function auto-assigns first available port number for socket.
}
function bindSocketToPort(port: int = -1): int;
//
// -- properties --
//
{DP:METHOD
Specifies remote host value for the socket. This value will be used to connect socket to.
}
property host: string read f_host write setHost;
{DP:METHOD
Specifies socket address family. For most applications you should use the AF_INET value.
}
property socketAddressFamily: int read f_socketAddressFamily write f_socketAddressFamily;
{DP:METHOD
Specifies protocol number to be used with socket. Following values are defined:
<UL>
<LI>IPPROTO_ICMP - control message protocol</LI>
<LI>IPPROTO_IGMP - group management protocol</LI>
<LI>IPPROTO_TCP - tcp</LI>
<LI>IPPROTO_UDP - user datagram protocol</LI>
</UL>
Other values are also defined in WinSock.pas
}
property socketProtocol: int read f_socketProtocol write f_socketProtocol;
{DP:METHOD
Specifies socket type to be used with socket. Following values are defined:
<UL>
<LI>SOCK_STREAM - stream socket
<LI>SOCK_DGRAM - datagram socket
<LI>SOCK_RAW - raw-protocol interface
</UL>
Other values are also defined in WinSock.pas
}
property socketType: int read f_socketType write f_socketType;
{DP:METHOD
Specifies IP address the socket should bind to.
Default value means the socket will bind to any availabe interface.
}
property bindToIP: string read f_bindToIP write f_bindToIP;
{DP:METHOD
Specifies Port name or number the socket should bind to.
Default value (0) means the socket will bind to first availabe port number.
Client sockets should always be bind to default port (0), unless you need some special behaviour.
}
property bindToPort: string read getBindToPort write setBindToPort;
{DP:METHOD
Returns True is socket is TCP server socket and is listening,
or if socket is TCP client and is connected, or if socket is bind to UDP port/interface.
Otherwise returns false.
}
property isActive: bool read getIsActive;
{DP:METHOD
Size of sending buffer.
}
property sndBufSize: unsigned index 0 read getBufSize write setBufSize;
{DP:METHOD
Size of receiving buffer.
}
property rcvBufSize: unsigned index 1 read getBufSize write setBufSize;
end;
//
// -- unaTcpSocket --
//
{DP:CLASS
This class encapsulates TCP socket implementation.
}
unaTcpSocket = class(unaSocket)
private
public
{DP:METHOD
Creates TCP socket.
}
constructor create();
end;
//
// -- unaUdpSocket --
//
{DP:CLASS
This class encapsulates UDP socket implementation.
}
unaUdpSocket = class(unaSocket)
private
public
{DP:METHOD
Creates UDP socket.
}
constructor create();
//
{DP:METHOD
Receives data from remote host. Flags could be 0, MSG_PEEK or MSG_OOB.
<BR />Returns 0 if data was received successfully, in which case from parameter will contain remote address data was sent from.
<BR />Returns specific WSA error otherwise.
}
function recvfrom(out from: sockaddr_in; var data: string; noCheck: bool = true; flags: unsigned = 0; timeout: unsigned = 3000): int; overload;
{DP:METHOD
Receives data from remote host. Flags could be 0, MSG_PEEK or MSG_OOB.
<BR />NOTE: Memory block pointed by data must be large enough to receive up to MTU bytes.
<BR />Returns size of data if it was received successfully, in which case from parameter will contain remote address data was sent from.
<BR />Returns 0 if the connection has been gracefully closed.
<BR />Returns SOCKET_ERROR if some error ocurred, or -2 if no data can be read at this time.
}
function recvfrom(out from: sockaddr_in; data: pointer; noCheck: bool = true; flags: unsigned = 0; timeout: unsigned = 3000): int; overload;
{DP:METHOD
Sends string of data to remote host. Flags could be 0, MSG_DONTROUTE or MSG_OOB.
<BR />Returns 0 if data was sent successfully, or specific WSA error otherwise.
}
function sendto(var addr: sockaddr_in; const data: string; flags: unsigned = 0; timeout: unsigned = 3000): unsigned; overload;
{DP:METHOD
Sends string of data to remote host. Flags could be 0, MSG_DONTROUTE or MSG_OOB.
<BR />If noCheck parameter is true it will not check the socket state before sending the data. This could be used to avoid unnecessary delays.
<BR />Returns 0 if data was sent successfully, or specific WSA error otherwise.
}
function sendto(var addr: sockaddr_in; const data: string; noCheck: bool = true; flags: unsigned = 0): unsigned; overload;
{DP:METHOD
Sends block of data to remote host. Flags could be 0, MSG_DONTROUTE or MSG_OOB.
<BR />If noCheck parameter is true it will not check the socket state before sending the data. This could be used to avoid unnecessary delays.
<BR />Returns 0 if data was sent successfully, or specific WSA error otherwise.
}
function sendto(var addr: sockaddr_in; data: pointer; size: unsigned; flags: unsigned = 0; timeout: unsigned = 3000; noCheck: bool = false): unsigned; overload;
{DP:METHOD
Sends block of data to remote host. Flags could be 0, MSG_DONTROUTE or MSG_OOB.
<BR />If noCheck parameter is true it will not check the socket state before sending the data. This could be used to avoid unnecessary delays.
<BR />Returns 0 if data was sent successfully, or specific WSA error otherwise.
}
function sendto(var addr: sockaddr_in; data: pointer; size: unsigned; noCheck: bool = true; flags: unsigned = 0): unsigned; overload;
end;
const
// NOTE: WinSock.pas (up to Delphi 2005) contains definitions of older values for IP_XXX constants
(*
* The following constants are taken from include/netinet/in.h
* in Berkeley Software Distribution version 4.4. Note that these
* values *DIFFER* from the original values defined by Steve Deering
* as described in "IP Multicast Extensions for 4.3BSD UNIX related
* systems (MULTICAST 1.2 Release)". It describes the extensions
* to BSD, SunOS and Ultrix to support multicasting, as specified
* by RFC-1112.
http://www.sockets.com/wsnp.htm
*)
{$EXTERNALSYM IP_MULTICAST_IF }
{$EXTERNALSYM IP_MULTICAST_TTL }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -