FB_LocalServer

FB_LocalServer 1:

Dem Server muss zuerst eine eindeutige sLocalHost-IP Adresse und eine nLocaPort-IP Portnummer zugewiesen werden. Beim gesetzten bEnable-Eingang versucht der Local-Server immer wieder nach Ablauf der SERVER_RECONNECT_TIME den Listener-Socket zu öffnen. Im Regelfall kann der Listener-Socket beim ersten Versuch geöffnet werden, wenn sich der TwinCAT TCP/IP Connection Server auf dem lokalen PC befindet. Die Funktionalität eines Remote-Clients wurde in dem Funktionsbaustein FB_RemoteClient gekapselt. Die Instanzen der Remote-Clients werden aktiviert, nachdem der Listener-Socket geöffnet werden konnte. Jede Instanz vom FB_RemoteClient entspricht einem Remote-Client mit dem der Local-Server gleichzeitig kommunizieren kann. Die maximale Anzahl der mit dem Server kommunizierenden Remote-Clients kann durch den Wert der MAX_CLIENT_CONNECTIONS-Konstanten verändert werden. Bei einem Fehler werden zuerst alle Remote-Client-Verbindungen und dann der Listener-Sockets geschlossen. Der nAcceptedClients‑Ausgang gibt Auskunft über die aktuelle Anzahl der verbundenen Clients.

Schnittstelle

FUNCTION_BLOCK FB_LocalServer
VAR_INPUT
    sLocalHost       : STRING(15) := '127.0.0.1';(* own IP address! *)
    nLocalPort       : UDINT := 0;
    bEnable          : BOOL;
END_VAR
VAR_OUTPUT
    bListening       : BOOL;
    hListener        : T_HSOCKET;
    nAcceptedClients : UDINT;
    bBusy            : BOOL;
    bError           : BOOL;
    nErrId           : UDINT;
END_VAR
VAR
    fbListen        : FB_SocketListen := ( sSrvNetID := '', tTimeout := DEFAULT_ADS_TIMEOUT );
    fbClose         : FB_SocketClose := ( sSrvNetID := '', tTimeout := DEFAULT_ADS_TIMEOUT );
    fbConnectTON    : TON := ( PT := PLCPRJ_RECONNECT_TIME );
    eStep           : E_ServerSteps;
    fbRemoteClient  : ARRAY[1..MAX_CLIENT_CONNECTIONS ] OF FB_RemoteClient;
    i               : UDINT;
END_VAR

Realisierung

CASE eStep OF

    SERVER_STATE_IDLE:
        IF bEnable XOR bListening THEN
            bBusy := TRUE;
            bError := FALSE;
            nErrId := 0;
            IF bEnable THEN
                fbConnectTON( IN := FALSE );
                eStep := SERVER_STATE_LISTENER_OPEN_START;
            ELSE
                eStep := SERVER_STATE_REMOTE_CLIENTS_CLOSE;
            END_IF
        ELSIF bListening THEN
            eStep := SERVER_STATE_REMOTE_CLIENTS_COMM;
        END_IF

    SERVER_STATE_LISTENER_OPEN_START:
        fbConnectTON( IN := TRUE, PT := PLCPRJ_RECONNECT_TIME );
        IF fbConnectTON.Q THEN
            fbConnectTON( IN := FALSE );
            fbListen( bExecute := FALSE );
            fbListen( sLocalHost:= sLocalHost,
                nLocalPort:= nLocalPort,
                bExecute    := TRUE );
                eStep := SERVER_STATE_LISTENER_OPEN_WAIT;
        END_IF

    SERVER_STATE_LISTENER_OPEN_WAIT:
        fbListen( bExecute := FALSE );
        IF NOT fbListen.bBusy THEN
            IF NOT fbListen.bError THEN
                bListening := TRUE;
                hListener := fbListen.hListener;
                eStep     := SERVER_STATE_IDLE;
                LogMessage( 'LISTENER socket OPENED!', hListener );
            ELSE
                LogError( 'FB_SocketListen', fbListen.nErrId );
                nErrId := fbListen.nErrId;
                eStep := SERVER_STATE_ERROR;
            END_IF
        END_IF

    SERVER_STATE_REMOTE_CLIENTS_COMM:
        eStep := SERVER_STATE_IDLE;
        nAcceptedClients := 0;
        FOR i:= 1 TO MAX_CLIENT_CONNECTIONS DO
            fbRemoteClient[ i ]( hListener := hListener, bEnable := TRUE );
            IF NOT fbRemoteClient[ i ].bBusy AND fbRemoteClient[ i ].bError THEN (*FB_SocketAccept returned error!*)
                     eStep := SERVER_STATE_REMOTE_CLIENTS_CLOSE;
                EXIT;
            END_IF
            (* count the number of connected remote clients *)
            IF fbRemoteClient[ i ].bAccepted THEN
                nAcceptedClients := nAcceptedClients + 1;
            END_IF
        END_FOR

    SERVER_STATE_REMOTE_CLIENTS_CLOSE:
        nAcceptedClients := 0;
        eStep := SERVER_STATE_LISTENER_CLOSE_START; (* close listener socket too *)
        FOR i:= 1 TO MAX_CLIENT_CONNECTIONS DO
            fbRemoteClient[ i ]( bEnable := FALSE );(* close all remote client (accepted) sockets *)
            (* check if all remote client sockets are closed *)
            IF fbRemoteClient[ i ].bAccepted THEN
                eStep := SERVER_STATE_REMOTE_CLIENTS_CLOSE; (* stay here and close all remote clients first *)
                nAcceptedClients := nAcceptedClients + 1;
            END_IF
        END_FOR

    SERVER_STATE_LISTENER_CLOSE_START:
        fbClose( bExecute := FALSE );
        fbClose(    hSocket := hListener,
                     bExecute:= TRUE );
        eStep := SERVER_STATE_LISTENER_CLOSE_WAIT;

    SERVER_STATE_LISTENER_CLOSE_WAIT:
        fbClose( bExecute := FALSE );
        IF NOT fbClose.bBusy THEN
            LogMessage( 'LISTENER socket CLOSED!', hListener );
            bListening := FALSE;
            MEMSET( ADR(hListener), 0, SIZEOF(hListener));
            IF fbClose.bError THEN
                LogError( 'FB_SocketClose (listener)', fbClose.nErrId );
                nErrId := fbClose.nErrId;
                eStep := SERVER_STATE_ERROR;
            ELSE
                bBusy := FALSE;
                bError := FALSE;
                nErrId := 0;
                eStep := SERVER_STATE_IDLE;
            END_IF
        END_IF

    SERVER_STATE_ERROR:
        bError := TRUE;
           IF bListening THEN
            eStep := SERVER_STATE_REMOTE_CLIENTS_CLOSE;
        ELSE
            bBusy := FALSE;
            eStep := SERVER_STATE_IDLE;
        END_IF

END_CASE