TWebServer / TSocket
Source: source/classes/twebserv.prg (TWebServer), source/classes/tsocket.prg (TSocket)
TWebServer is FiveWin's built-in HTTP server that can serve HTML pages, process GET/POST requests, and merge dynamic content into HTML templates. It is built on top of TSocket, which provides low-level TCP/IP socket communication using the Windows Winsock API.
Architecture
flowchart TD
subgraph "TWebServer"
A[oSocket
Listening Socket] B[OnAccept] C[OnRead] D[OnGet / OnPost] E[HtmlMerge
Template Engine] end subgraph "TSocket Layer" F[WSAStartup] G["Socket(AF_INET, SOCK_STREAM)"] H[Listen / Accept] I[SendData / GetData] end subgraph "Clients" J[Browser 1] K[Browser 2] L[API Client] end J -->|"HTTP GET/POST"| A K --> A L --> A A --> B B --> C C --> D D --> E A --> F F --> G G --> H H --> I
Listening Socket] B[OnAccept] C[OnRead] D[OnGet / OnPost] E[HtmlMerge
Template Engine] end subgraph "TSocket Layer" F[WSAStartup] G["Socket(AF_INET, SOCK_STREAM)"] H[Listen / Accept] I[SendData / GetData] end subgraph "Clients" J[Browser 1] K[Browser 2] L[API Client] end J -->|"HTTP GET/POST"| A K --> A L --> A A --> B B --> C C --> D D --> E A --> F F --> G G --> H H --> I
TWebServer Class
Key DATA Members
| DATA | Type | Default | Description |
|---|---|---|---|
oSocket | TSocket | Main listening socket object | |
aSockets | Array | Array of client socket objects | |
cAddress | Character | Server IP address | |
cDefPage | Character | "default.htm" | Default page to serve |
cDefPath | Character | "www" | Root directory for web pages |
cCookie | Character | Current request cookie data | |
lDebug | Logical | .F. | Enable debug logging |
cLogFile | Character | "" | Log file path |
cHtmlError | Character | HTML to show on file-not-found errors |
Methods
| Method | Description |
|---|---|
New( nPort ) | Create server on specified port (default: 80). Creates "www" directory if missing. |
Activate() | Start listening for connections |
Explore( cHtmlFile ) | Open the page in the default browser via ShellExecute |
OnAccept() | Handle new client connection (creates client TSocket) |
OnRead( oSocket ) | Read incoming data, dispatch to OnGet/OnPost |
OnGet( oClientSocket, cData ) | Handle HTTP GET requests |
OnPost( oClientSocket, cData ) | Handle HTTP POST requests |
HtmlMerge( cHtml, cParams, mSocket, cQuery ) | Merge dynamic content into HTML templates |
HtmlRead( cFileName ) | Read an HTML file from disk |
FileExist( cFileName ) | Check if a file exists in the web root |
End() | Stop the server and close all sockets |
TSocket Class
Key DATA Members
| DATA | Type | Default | Description |
|---|---|---|---|
nPort | Numeric | 0 | Socket port number |
cIPAddr | Character | "" | Socket IP address |
nSocket | Numeric | -1 | Winsock socket handle |
nTimeOut | Numeric | 30 | Timeout in seconds |
nBackLog | Numeric | 5 | Listen backlog size |
bAccept | Block | Callback when a connection is accepted | |
bRead | Block | Callback when data is available to read | |
bWrite | Block | Callback when socket is ready to write | |
bClose | Block | Callback when socket is closed | |
bConnect | Block | Callback on outgoing connection result | |
lDebug | Logical | Enable debug logging | |
cLogFile | Character | Log file path |
Methods
| Method | Description |
|---|---|
New( nPort, oWnd, cIp ) | Create a socket. Calls WSAStartup if first socket. |
Listen() | Start listening for incoming connections |
Accept( nSocket, oWnd ) | Accept an incoming connection, returns new TSocket |
Connect( cIPAddr, nPort ) | Connect to a remote server |
GetData() | Read data from the socket |
SendData( cData ) | Send string data through the socket |
SendFile( cFileName, nBlockSize ) | Send a file through the socket |
SendChunk( nBlockSize ) | Send data in chunks (for large transfers) |
ClientIP() | Get the connected client's IP address |
Close() | Close the socket |
End() | Close and clean up |
Example: Basic HTTP Server
#include "FiveWin.ch"
function Main()
local oWnd, oWS
DEFINE WINDOW oWnd TITLE "FiveWin Web Server"
// Create web server on port 8080
oWS := TWebServer():New( 8080 )
oWS:cDefPath := "www"
oWS:cDefPage := "index.html"
oWS:Activate()
// Open browser
oWS:Explore( "index.html" )
ACTIVATE WINDOW oWnd ;
VALID ( oWS:End(), .T. )
return nil
Example: Dynamic Content
#include "FiveWin.ch"
function Main()
local oWnd, oWS
DEFINE WINDOW oWnd TITLE "Dynamic Web Server"
oWS := TWebServer():New( 8080 )
oWS:lDebug := .T.
oWS:cLogFile := "webserver.log"
oWS:Activate()
oWS:Explore()
ACTIVATE WINDOW oWnd VALID ( oWS:End(), .T. )
return nil
Create www/default.htm with dynamic placeholders:
<html>
<head><title>FiveWin WebServer</title></head>
<body>
<h1>Welcome to FiveWin WebServer</h1>
<p>Server Time: <%=Time()%></p>
<p>Date: <%=DToC(Date())%></p>
<p>Records in Customers: <%=LTrim(Str(RecCount()))%></p>
<form method="POST" action="search.htm">
Search: <input type="text" name="query">
<input type="submit" value="Go">
</form>
</body>
</html>
Example: Raw TCP Socket Client
#include "FiveWin.ch"
function Main()
local oSocket, cResponse
oSocket := TSocket():New( 0 )
// Connect to a remote server
oSocket:Connect( "93.184.216.34", 80 ) // example.com
// Send HTTP request
oSocket:SendData( ;
"GET / HTTP/1.1" + CRLF + ;
"Host: example.com" + CRLF + ;
"Connection: close" + CRLF + CRLF )
// Read response
oSocket:bRead := { |oSock|
cResponse := oSock:GetData()
? cResponse
}
oSocket:bClose := { |oSock|
? "Connection closed"
oSock:End()
}
// Process events (in a real app, the message loop handles this)
SysRefresh()
Inkey( 5 )
oSocket:End()
return nil
Example: Simple Chat Server
#include "FiveWin.ch"
static aClients := {}
function Main()
local oWnd, oSocket
DEFINE WINDOW oWnd TITLE "Chat Server - Port 9000"
oSocket := TSocket():New( 9000 )
oSocket:bAccept := { ||
local oClient := TSocket():Accept( oSocket:nSocket )
AAdd( aClients, oClient )
oClient:bRead := { |oSock|
local cMsg := oSock:GetData()
// Broadcast to all clients
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()
}
}
oSocket:Listen()
ACTIVATE WINDOW oWnd VALID ( oSocket:End(), .T. )
return nil
Notes
- TWebServer creates a
wwwdirectory automatically if it does not exist, with a default HTML page. - The
HtmlMerge()method processes<%=expression%>tags in HTML files, evaluating Harbour expressions and embedding results. - Cookie data from HTTP requests is automatically parsed and stored in
oWS:cCookie. - TSocket uses Windows async socket events (FD_READ, FD_WRITE, FD_ACCEPT, FD_CLOSE) via the message loop, so it works seamlessly with FiveWin's event-driven architecture.
- For production use, consider using a reverse proxy (nginx, Apache) in front of TWebServer for SSL termination and static file serving.