TSocket
Source: source/classes/tsocket.prg
TSocket is FiveWin's low-level TCP/IP socket class, wrapping the Windows Winsock API. It provides both client and server socket functionality through an asynchronous, event-driven model that integrates naturally with FiveWin's message loop. TSocket is the foundation for TWebServer, TSmtp, TPop3, TFtpClient, and TWebClient.
Architecture
flowchart LR
subgraph "FiveWin Application"
A[TSocket]
B[oWnd
Message Loop] end subgraph "Event Callbacks" C[bAccept
bRead
bWrite] D[bClose
bConnect
bOOB] end subgraph "Winsock API" E[WSASocket] F[bind / listen] G[accept / connect] H[send / recv] end A -->|"WSAAsyncSelect"| B A --> C A --> D A --> E E --> F F --> G G --> H
Message Loop] end subgraph "Event Callbacks" C[bAccept
bRead
bWrite] D[bClose
bConnect
bOOB] end subgraph "Winsock API" E[WSASocket] F[bind / listen] G[accept / connect] H[send / recv] end A -->|"WSAAsyncSelect"| B A --> C A --> D A --> E E --> F F --> G G --> H
Key DATA Members
| DATA | Type | Default | Description |
|---|---|---|---|
nPort | Numeric | 0 | Socket port number |
cIPAddr | Character | "" | Local IP address (auto-detected on creation) |
nSocket | Numeric | -1 | Winsock socket handle |
nTimeOut | Numeric | 30 | Timeout in seconds for operations |
nBackLog | Numeric | 5 | Maximum pending connections for listening |
bAccept | Block | Callback when a new connection is accepted (server mode) | |
bRead | Block | Callback when data is available to read | |
bWrite | Block | Callback when the socket is ready to write | |
bClose | Block | Callback when the remote end closes the connection | |
bConnect | Block | Callback with connection result (client mode) | |
bOOB | Block | Callback for out-of-band data | |
lDebug | Logical | Enable debug logging | |
cLogFile | Character | Path for debug log file | |
aBuffer | Array | {} | Internal buffer for queued outgoing data |
lSending | Logical | Whether a send operation is in progress | |
aSockets | Array (Class) | {} | Class-level array tracking all active sockets |
Methods
| Method | Description |
|---|---|
New( nPort, oWnd, cIp ) | Create a socket and bind to port. Calls WSAStartup on first socket. Registers with oWnd for async events. |
Listen() | Start listening for incoming connections on the bound port |
Accept( nSocket, oWnd ) | Accept an incoming connection. Returns a new TSocket for the client session. |
Connect( cIPAddr, nPort ) | Connect to a remote server as a client |
GetData() | Read available data from the socket. Returns a character string. |
SendData( cData ) | Send character data. Buffers data if a previous send is in progress. |
SendFile( cFileName, nBlockSize ) | Send a file in blocks. Default block size is 30,000 bytes. |
SendChunk( nBlockSize ) | Send the next block from an open file handle (used internally by SendFile) |
ClientIP() | Get the IP address of the connected remote peer |
Refresh() | Force the socket to re-register for async events |
Close() | Close the socket handle. Waits for pending sends to complete. |
End() | Close the socket and remove from the class-level socket list. Calls WSACleanup when last socket. |
Event Callbacks
TSocket uses WSAAsyncSelect to register for Windows socket events. When an event occurs,
the FiveWin message loop routes it to HandleEvent(), which dispatches to the appropriate
callback method. Set the corresponding codeblock to handle the event:
| Codeblock | Event | Callback Method |
|---|---|---|
bAccept | Incoming connection | OnAccept() |
bRead | Data available | OnRead() |
bWrite | Ready to send | OnWrite() |
bClose | Remote closed | OnClose() |
bConnect | Connection result | OnConnect( nErrorCode ) |
bOOB | OOB data | OnOOB() |
Example: TCP Client
#include "FiveWin.ch"
function Main()
local oWnd, oSocket, cResponse := ""
DEFINE WINDOW oWnd TITLE "TCP Client"
oSocket := TSocket():New( 0, oWnd )
oSocket:bRead := { |oSock|
cResponse += oSock:GetData()
oWnd:SetText( "Received: " + cResponse )
}
oSocket:bClose := { |oSock|
MsgInfo( "Connection closed" )
oSock:End()
}
// Connect to a remote server
oSocket:Connect( "93.184.216.34", 80 )
// Send HTTP request
oSocket:SendData( "GET / HTTP/1.1" + CRLF + ;
"Host: example.com" + CRLF + ;
"Connection: close" + CRLF + CRLF )
ACTIVATE WINDOW oWnd ;
ON INIT SysRefresh() ;
VALID ( oSocket:End(), .T. )
return nil
Example: Chat Server
#include "FiveWin.ch"
static aClients := {}
function Main()
local oWnd, oSocket
DEFINE WINDOW oWnd TITLE "Chat Server - Port 9000"
oSocket := TSocket():New( 9000, oWnd )
oSocket:Listen()
oSocket:bAccept := { ||
local oClient := TSocket():Accept( oSocket:nSocket, oWnd )
AAdd( aClients, oClient )
oClient:bRead := { |oSock|
local cMsg := oSock:GetData()
AEval( aClients, { |o| o:SendData( cMsg ) } )
}
oClient:bClose := { |oSock|
local nAt := AScan( aClients, ;
{ |o| o:nSocket == oSock:nSocket } )
if nAt > 0
ADel( aClients, nAt, .T. )
endif
oSock:End()
}
}
ACTIVATE WINDOW oWnd VALID ( oSocket:End(), .T. )
return nil
Notes
- TSocket requires a FiveWin window (or dialog) for its async event model. The window's message loop dispatches Winsock events via
WSAAsyncSelect. - The class-level
aSocketsarray tracks all live sockets.HandleEvent()searches this array by socket handle to dispatch events to the correct object. WSAStartup()is called when the first TSocket is created.WSACleanup()is called when the last socket is destroyed.- The
SendData()method handles partial sends and buffers data automatically. Large sends are transparently split across multiple TCP segments. - Use
ShowIP()(a utility function in tsocket.prg) to quickly get the local machine's IP address.