⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 unasockets.pas

📁 Voice Commnucation Components for Delphi
💻 PAS
📖 第 1 页 / 共 5 页
字号:

(*
	----------------------------------------------

	  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 + -