Return to WWW.WARD.NU
|The TSock Component
Freeware Windows Socket Component For Delphi & C++ Builder
Version 1.0k, tested with Delphi 2.0, 3.0 & 4.0
Written By Tom Bradford
Maintained By Ward van Wanrooij (firstname.lastname@example.org, http://www.ward.nu)
© 1997-2000, Beach Dog Software, Inc.
Latest version can be obtained at http://www.ward.nu/computer/tsock
Return to WWW.WARD.NU
Why use TSock and not [...]
Welcome to the 1.0k release of TSock. TSock is a Delphi component which wraps basic WinSock functionality and provides some support functions for writing networked applications. TSock is released as freeware and ships with complete source code! If you are upgrading from a previous version, please check-out the release notes first!
If you are able to isolate and fix a bug in the component, please email the changes to Ward van Wanrooij for incorporation into future releases of the component. The point of TSock is to make it easier for everyone who develops socket applications. Please do not redistribute modified versions of the TSock component.
Because it is freeware, there is no charge for using this component in your own applications. Be aware that you use the component at your own risk. Beach Dog Software, Tom Bradford and Ward van Wanrooij are in no way responsible for anything bad that might happen through the product's use. When you do use it though, please give us credit for the component, and maybe a hyperlink to our site. It would be nice.
TSock has been developed by Tom Bradford of Beach Dog Software. Development started in 1997 and halted in 2000, when Beach Dog Software closed it's doors and Tom went to the dbXML Group. Since this moment, Ward van Wanrooij is the custodian and maintainer of this excellent piece of software.
Table Of Contents
Why use TSock and not [...]
Other socket components exist, like WinShoes and Internet Component Suite, which consist of several components. For example the TWinshoeHTTPClient provides an easy way to download web pages.
Why do you want to use TSock instead of these components?
- Because all of the TSock functionality is contained in one .pas file, consisting of 1336 lines of code (version 1.0h), learning sockets programming using TSock is far easier than learning using another component.
- You want to design your own network communication protocol for [insert your networked application name]. ICS and WinShoes also do a good job at this, but TSock was designed for this.
- You like TSock better. Just like me.
Table Of Contents
You are free download the TSock package or view the source code online.
It is highly recommended that you subscribe to the mailinglist to keep up-to-date about new releases.
Table Of Contents
1.0k Release Notes
- Fixed a bug in the ReceiveLine method, bugfix submitted by Korhan Kaya.
- Fixed a bug in the ReceiveDatagram method, bugfix submitted by both Dave007 and Steffen Kirbach.
- Addition of a new method: SendLine
- Cleaning up of the default samples.
1.0j Release Notes
- Fixed a bug in the smart line ending detection routine, bugfix submitted by Sasaki Takeru.
- Fixed a bug in the demo programs, concerning TSock child enumerations.
1.0i Release Notes
- Ward moved all the examples into the 'old_samp' directory and provided two all new examples. The two new examples are server applications, one blocking and one non-blocking. The examples have been programmed in a clean programming style, and checked for memory issues and exception handling. They can be used as a starting point for your own application. An additional example (showing UDP broadcasting of a Delphi record to a Linux server running standard services (Cool!)) is available at http://www.ward.nu/computer/rwhodwin.
- Ward fixed a bug in AutoAccept, the GetRemoteHost function would not work on the autoaccepted TSock. Added a read-only, runtime property RecvAddrIn. In normal life, you probably never need it, read the source for more information.
- Ward fixed some memory issues (FStream) and improved memory, thread and component handling when using AutoAccept. When using blocking AutoAccept, the autoaccepted TSock is freed at thread termination (=the end of TSock.OnAutoAccept), when using non-blocking AutoAccept, the autoaccepted TSock is freed at the closing of the autoaccepted TSock. Previously, you could access these TSocks after they were closed (because they were never freed!), so test your application carefully when compiling using the 1.0i release.
- Ward improved the handling of unexpected disconnects and errors, this improves reliability, especially in the blocking edition.
- Ward made some small bugfixes in FD_CLOSE and HostLookup.
- Ward has added the method GetLocalHostname .
- Ward removed the references to beachdogsoftware.com from the source, since this domain is not active anymore. Also moved the component to the 'Ward' tab.
1.0h Release Notes
- The component is now maintained by Ward van Wanrooij and has a new address for updates: http://www.ward.nu/computer/tsock.
- Ward changed some IFDEF's for compatibility.
- Ward modified URLEncode to be RFC 1630 compliant.
- Ward added the property LocalPortName. LocalPortName defaults to -1, which corresponds to LocalPortName=PortName, for backward compatibility.
- Ward has revised the method Open quite a bit.
1.0g Release Notes
- I fixed a nasty bug in the TSockThread class that would cause the handler thread to be freed, but not terminated. This has been repaired.
1.0f Release Notes
- I Added the BlockingTimeout property. BlockingTimeout will force TSock to wait for a specific number of milliseconds while attempting to fill its receive buffer. Receives will return when the buffer is filled or when the blocking timeout has elapsed with no data.
- I Added the Stream property. Stream returns a TStream compatible object for performing Stream I/O on a TSock instance.
- I Added the ReceiveCount method. ReceiveCount allows you to limit the size of the receive buffer.
- I entirely rewrote the threading mechanism used by TSock for AutoAccept Blocking Servers. The older mechanism relied on Win32 C-Style CreateThread coding, which caused Delphi to leak resources and blow up upon program termination. The new mechanism uses Delphi's TThread objects to perform multi-threading, which is a lot safer.
1.0e Release Notes
- I was finally able to isolate and squash the TSock.Free bug. It was a really stupid oversight on my part and I should be shot for it.
- I have decided to release the TSock source code to the general public. I think it is better that others have access to the source code to help debug and troubleshoot, as well as help us add features to the component.
Release Notes Prior To 1.0e
- A bug was found in the reporting of error status that would cause a false onConnect event to be reported. This bug has been stomped.
- A bug was found in the dynamic creation of asynchronous sockets that caused I/O to become non-responsive. This problem has been remedied.
- A bug was found in Datagram Sockets that was not caught in our final QA. This problem has been corrected.
- A bug was found in ReceiveLine. ReceiveLine short-circuited on Blocking Sockets if the the socket closed and there was still data in the input buffer. This has been remedied. In order to fix the problem, I have added a property called EndOfFile. EndOfFile will return TRUE if the socket is no longer connected and the input buffer is empty. You should use EndOfFile if you are performing buffered input using ReceiveLine.
- TSock now caches IP addresses in the IPCache global variable. A user shouldn't have to interact with this variable directly. If you need to clear the cache, call the IPCache.Clear method.
- Connected is now determined in two places during normal operation. With a non-blocking socket, Connected is set to TRUE by an FD_CONNECT message and set to FALSE by an FD_CLOSE message. With a blocking socket, Connected is set to TRUE by the socket being opened and set to FALSE by Receive returning 0 content when it performs a WinSock recv.
- TSock allows its Socket property to be assigned. When you assign this property, the component will perform a GetSockOpt to verify that SO_ACCEPTCONN (indicates Listening) doesn't return TRUE. If it does return TRUE, I throw an exception. The socket can't verify that there isn't some other process monitoring the socket, so it will not allow you to assign a listening socket to it.
- The Blocking property has been rewritten so that you can set it even when a connection is present. If set to TRUE, the asynchronous message hook is disabled, and IOCtlSocket is used to turn blocking on. If set to FALSE, the asynchronous message hook is installed. Please note that the TSock events act differently in Blocking and Non-Blocking mode... In asynchronous mode, all events prompt the implementer to perform some action. In blocking mode, with the exception of OnAccept and OnAutoAccept, if an event is triggered at all, it is usually to report some sort of status.
- When dynamically creating a TSock control, it is recommended that you perform an InsertControl to insert the component into an appropriate container. The control requires a Parent to allocate a window handle. If Parent has not been set, the control will use Screen.Forms as a Parent. Window handles are required to perform asynchronous non-blocking socket calls.
Table Of Contents
- Package caches resolved IP Addresses for faster DNS lookups.
- Supports both TCP and UDP protocols.
- Listening mode will automatically accept incoming connections, create a new TSock component for the connected socket, and spawn a new thread of execution to handle concurrent blocking server connections.
- Support for blocking and non-blocking socket communications.
- Component can transfer blocks of data up to 4 gigabytes in length.
- MIME-standard Base-64 encoding and decoding routines.
- URL encoding and decoding routines.
- Robust state information messaging system for diagnostics and status.
- Support for multiple connections utilizing multiple-threads.
Table Of Contents
|AutoAccept||Boolean||Design||Auto-Accept Incoming Connections. TRUE causes a Listening socket (Listen = TRUE) to automatically accept an incoming connection and call OnAutoAccept as a new thread. If no OnAutoAccept is defined, OnAccept is called. If No OnAccept is defined, the incoming connection will linger.|
|Blocking||Boolean||Design||Blocking Socket I/O. TRUE causes a socket to block while connecting, waiting for incoming data and writing to the socket. FALSE causes an asynchronous window message to be sent when a connection is made, data is available to be read and written.|
|BlockingTimeout||Integer||Design||BlockingTimeout will force TSock to wait for a specific number of milliseconds while attempting to fill its receive buffer. Receives will return when the buffer is filled or when the blocking timeout has elapsed with no data.|
|Connected||Boolean||RunTime||Connect Socket Or Check Connection. If set to TRUE, the component attempts to open a socket connection. If set to FALSE, the component closes a current connection. If the value returned is TRUE, the socket is connected, otherwise, it is not.|
|EndOfFile||Boolean||RunTime||EndOfFile will return TRUE if the socket is no longer connected and the input buffer is empty. You should use EndOfFile if you are performing buffered input using ReceiveLine.|
|HostName||String||Design||Host Name or IP Address. The Socket Component will automatically distinguish a Host Name (ex: www.cinteractive.com) from an IP Address (ex: 127.0.0.1).|
|LineBreak||TLineBreak||Design||Sets the method of scanning incoming data for possible line breaks. This property is used in cooperation with the ReceiveLine method for reading an incoming data stream 1 text line at a time. The possible values for this property are lbCR, lbLF, lbCRLF and lbSmart. lbSmart will make guesses as to the form of the incoming data stream based upon content and break the lines accordingly.|
|Listen||Boolean||Design||Listen For Incoming Connections. If TRUE, creates a thread that loops, listening for incoming sockets and handling them based on the AutoAccept, OnAccept, and OnAutoAccept properties.|
|LocalPortName||String||Design||-1 means LocalPortName=PortName, 0 means I Really Don't Care (using the standard Microsoft Winsock2 Stack, this translates to a semi-random port from 1024-5000), >1 means that port number, a String means that Service Name. LocalPortName defaults to -1 for backward compatibility reasons. It is recommended for client applications to use 0.|
|PortName||String||Design||Port Number or Service Name. Port Numbers are well known ports such as 80 for HTTP or 7 for Echo. Service Names perform a database lookup into the SERVICES file.|
|RecvAddrIn||TSockAddrIn||RunTime||Provides a readonly datastructure describing the remote host. You will probably never need this, since RemoteHost wraps most of its functionality.|
|RemoteHost||String||RunTime||RemoteHost returns the remote IP address if SocketType=stStream (TCP) or the IP address of the most recent incoming datagram if SocketType=stDatagram (UDP).|
|Socket||TSocket||RunTime||Returns Socket Value. Returns the value of a connected socket. Returns INVALID_SOCKET (-1) if the socket isn't currently connected. This property also allows the user to set the value of the socket, but this is inadvisable.|
|SocketType||TSocketType||Design||Type of socket. This value can either be stStream or stDatagram. If Listen is set to TRUE, this property will automatically be set to stStream because Datagram sockets do not support listening mode. Likewise, if the socket type is set to stDatagram, the Listen property will be set to False (in design mode).|
|Stream||TStream||RunTime||Returns a TStream compatible object to allow performing Stream-based I/O on a TSock instance.|
|Text||String||RunTime||Sends And Receives Text. If being assigned to, the value being assigned will be sent to the socket. If being read from, any incoming data from the socket will be returned.|
Table Of Contents
|Occurs when a socket is in queue to be accepted. This event can be used in cooperation with the Accept method to perform multi-client server operations.|
|Occurs when AutoAccept is TRUE. Creates a new client socket and invokes OnAutoAccept as a thread separate from the main application. It is no longer the implementer's responsibility to Free the TSock component that is passed.|
|Occurs when a client socket connects to a remote host.|
|Occurs when a client socket disconnects from a remote host or when the connection is unexpectedly terminated.|
(TObject, TSocketInfo, String)
|Occurs when the component produces a state message. This event sends a TSocketInfo parameter as well as a string with information specific to the task that is being reported on.|
|Occurs when data is available to be read from the socket.|
|Occurs when the socket will allow data to be written.|
Table Of Contents
|Accept(TSock) : Boolean||Accepts the next available incoming socket from the listening loop. Accept return TRUE if successful. This method also assigned the TSock parameter to a valid TSock connection component. It is the implementer's responsibility to Free this component when it is no longer needed. Also, the new component is created with no Event handlers, so the implementer is responsible for assigning them if the socket is non-blocking. This event will only be triggered if Listen is TRUE.|
|Close : Boolean||Closes any existing remote connection.|
|Open : Boolean||Opens a connection to the remote HostName using PortName. Returns TRUE if successful. Returns FALSE if the connection could not be established.|
|Receive : String||Returns any incoming data from the socket. Will block while waiting for data if Blocking is set to TRUE and no data is available in the queue.|
|ReceiveCount(Integer) : String||ReceiveCount allows you to limit the size of the receive buffer. ReceiveCount doesn't necessarily force the size of the returned string, but does ensure that BlockingTimeout will return when it is able to fill to requested buffer size.|
|ReceiveDatagram(Var String) : String||Returns a string with the Datagram content received from any address through the bound UDP PortName. ReceiveDatagram will set the String parameter to the IP address of the Datagram's originator.|
|ReceiveLine : String||Returns the next input line from the input stream for a socket with SocketType set to stStream. This method uses the LineBreak property to determine how to scan the input stream. If the SocketType is set to stDatagram, this method returns the next incoming Datagram in its entirety. Because the entire Input Stream isn't returned by this method, the socket may have already determined that the connection has been closed. In this case, it is the user's responsibility to check for incoming data even if the socket is no longer connected.|
|Send(String) : Boolean||Sends a string to the remote connection. Returns TRUE if successful.|
|SendLine(String) : Boolean||Sends a line to the remote connection. Returns TRUE if successful.|
|SendDatagram(String, String) : Boolean||Sends the text in the first String parameter as a Datagram to the HostName address defined in the second String parameter. Because UDP is by-definition unreliable, this method always returns TRUE.|
|StartListen : Boolean||Sets the socket component into listening mode. The result is TRUE if successful and FALSE otherwise. This method is the same as setting Listen=TRUE and then checking the value of Listen.|
|StopListen : Boolean||Turns listening mode off.|
|HostLookup(String) : TInAddr||Looks up a remote host using the String parameter. The parameter can either be an IP address (ex: 126.96.36.199) or a domain name (ex: www.cinteractive.com). The value that is returned is a TInAddr structure that can be used when building a TSockAddrIn for binding a socket to an address.|
|PortLookup(String) : Word||Looks up a service port using the String parameter. The parameter can either be a textual service name (ex: echo or Finger) or a port number (ex: 80). The value that is returned is a unsigned short in network byte order.|
Table Of Contents
|WSDescription : String||Returns a vendor-defined string that describes the presently running WinSock implementation. This information is obtained while performing an initial WSAStartup WinSock call.|
|WSASystemStatus : String||Returns a vendor-defined string containing system status.|
|GetLocalHostname : String||Retrieves the local hostname. The local hostname is often not a FQDN (Fully Qualified Domain Name), and it's implementation differs in WinSock 1.1 and WinSock 2.0. Only to be used for informational purposes, nothing connection critical.|
|SocketInfoText(TSocketInfo) : String||Given the TSocketInfo parameter, returns a string that describes the parameter. This function can be used in conjunction with an OnInfo event.|
|ErrToStr(Integer) : String||Given the Integer parameter, returns the WinSock defined string associated with a particular error code. TSock uses this support routine internally for translating asynchronous errors to TSockException exceptions.|
|Base64Encode(String) : String||Converts the String parameter to a MIME-standard Base-64 encoded block and returns the conversion as the String result.|
|Base64Decode(String) : String||Converts the String parameter from a MIME-standard Base-64 encoded block and returns the conversion as the String result.|
|URLEncode(String) : String||Converts the String parameter to a URLEncoding scheme and returns the conversion as the String result.|
|URLDecode(String) : String||Converts the String parameter from a URLEncoding scheme and returns the conversion as the String result.|
Table Of Contents
There are a few sample applications ready. The examples in the 'old_samp' directory have not been checked for memory issues or exception handling, and can be flaky.
- blocking is an example of using blocking, listening, multithreading sockets and providing a graceful shutdown. Run blocking and connect using telnet.exe tot 127.0.0.1 port 2876 to test. You can use this example as starting point for your own blocking server application.
- nonblock is an example of using non-blocking, listening sockets and providing a graceful shutdown. Run nonblock and connect using telnet.exe tot 127.0.0.1 port 2876 to test. This example has exactly the same functionality as it's blocking counterpart. Although you can use this example as starting point for your own non-blocking server application, I would recommend using the blocking version (see source).
- RWho Daemon for Windows is not included in the sample package, but it is a really good example, of how extremely easy TSock is to use. It shows UDP broadcasting of a Delphi record to a Linux server running standard services (Cool!).
- old_samp\UDPTester is a Datagram testing program that implements a simple chat system.
- old_samp\SockTest is a general purpose socket testing client. It demonstrates the non-blocking application of the TSock component. It allows a user to open any port on any host, send any data, and watch what comes back.
- old_samp\SrvTest is an implementation of the Echo protocol. This protocol is simple. Once the server answers, it spits back whatever the client sends to it. This application demonstrates how to write a multi-threaded blocking server.
- old_samp\Test64 is a general-purpose Base-64 and URL encoding and decoding tester.
- old_samp\Proxy is a simple HTTP proxy server. It demonstrates how to write a multi-threaded blocking server as well as how to dynamically create TSock objects and connect them to a remote port. The proxy server itself does not perform content caching but it serves as a good starting point for a custom implementation.
Table Of Contents