TSocket

Fonte: 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

Key DATA Members

DATATypeDefaultDescription
nPortNumeric0Socket port number
cIPAddrCharacter""Local IP address (auto-detected on creation)
nSocketNumeric-1Winsock socket handle
nTimeOutNumeric30Timeout in seconds for operations
nBackLogNumeric5Maximum pending connections for listening
bAcceptBlockCallback when a new connection is accepted (server mode)
bReadBlockCallback when data is available to read
bWriteBlockCallback when the socket is ready to write
bCloseBlockCallback when the remote end closes the connection
bConnectBlockCallback with connection result (client mode)
bOOBBlockCallback for out-of-band data
lDebugLogicalEnable debug logging
cLogFileCharacterPath for debug log file
aBufferArray{}Internal buffer for queued outgoing data
lSendingLogicalWhether a send operation is in progress
aSocketsArray (Class){}Class-level array tracking all active sockets

Methods

MethodDescription
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:

CodeblockEventCallback Method
bAcceptIncoming connectionOnAccept()
bReadData availableOnRead()
bWriteReady to sendOnWrite()
bCloseRemote closedOnClose()
bConnectConnection resultOnConnect( nErrorCode )
bOOBOOB dataOnOOB()

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

Veja Também