Programmierung

Message Exchange (MSX-Befehle Teil 2)

Wie ich bereits in Message Exchange (MSX-Befehle Teil 1) erwähnt habe, möchte ich in diesem Artikel etwas näher auf die Verwendung der einzelnen MSX-Befehle eingehen.


Die MSX-Befehle im Überblick:
  • MsxOpen() Öffnet einen Nachrichtenkanal
  • MsxWrite() Schreibt in einen Nachrichtenkanal
  • MsxRead() Liest aus einem Nachrichtenkanal
  • MsxWriteMem() Schreibt aus einem Memory-Objekt in einen Nachrichtenkanal
  • MsxReadMem() Liest aus einem Nachrichtenkanal in ein Memory-Objekt
  • MsxClose() Schließt einen Nachrichtenkanal

MsxOpen()

Um einen Nachrichtenkanal zu öffnen, wird der Befehl MsxOpen() verwendet. Dabei wird ein 16 KB großer Puffer für die Msx-Nachricht angelegt. Ist dieser Puffer voll, wird der Inhalt, je nach Kommunikationstyp, entweder in die Warteschlange, in die Datei oder auf den Socket geschrieben. Dadurch ist der Puffer wieder leer und kann erneut beschrieben werden.

Die Art der Kommunikation und die Zugriffsrechte werden im ersten Parameter angegeben.

Zur Verfügung stehen:

_MsxSocket
Kommunikation über Socket-Verbindung

_MsxFile
Kommunikation über externe Datei

_MsxThread
Kommunikation mit einem als Thread gestarteten Job

_MsxProcess
Kommunikation mit einem als Prozess gestarteten Job

_MsxRead
Lesender Zugriff

_MsxWrite
Schreibender Zugriff

Es kann nur eine Konstante für die Verbindung mit einer Konstante für die Datenrichtung kombiniert werden. Ein Nachrichtenkanal kann nur zum Lesen oder zum Schreiben benutzt werden, nicht aber für beides. Um sowohl lesen und schreiben zu können, müssen zwei Nachrichtenkanäle geöffnet werden. Einen zum Lesen und einen zum Schreiben. Bei der Kommunikation über Socket, kann so über die selbe Verbindung eine Full-duplex Verbindung ermöglicht werden.

Im zweiten Parameter wird der entsprechende Deskriptor (Socket-Verbindung, geöffnete Datei oder Job) übergeben. Hierbei ist zu beachten, dass dieser Deskriptor bis zum MsxClose() nicht weiter verwendet werden sollte. Da sich die Daten der Msx-Nachrichten z.B. mit denen des SckWrite() vermischen könnten und so ein schwer interpretierbares Durcheinander entsteht.

Der Rückgabewert der Funktion ist der Deskriptor des Nachrichtenkanals.

// Nachricht über Socket versenden
tSck # SckConnect('10.1.1.16',1250);
if (tSck > 0)
{
  tMsx # MsxOpen(_MsxSocket | _MsxWrite, tSck);
  ...

// Nachricht aus externer Datei lesen
tFile # FsiOpen(tFileName,_FsiStdRead);
if (tFile > 0)
{
  tMsx # MsxOpen(_MsxFile | _MsxRead, tFile);
  ...

MsxWrite()

Wie im letzten Artikel bereits erwähnt, besteht eine Nachricht aus mehreren Teilen. Mit Hilfe des Befehls MsxWrite() können diese Nachrichtenteile in den Nachrichtenkanal geschrieben werden. Dabei wird der Funktion übergeben welcher Teil der Nachricht beschrieben werden soll und welche Daten er enthält.

_MsxMessage

Damit wird eine neue Nachricht geöffnet, eine bereits geöffnete wird automatisch geschlossen. Im dritten Parameter muss ein Wert vom Typ int ungleich 0 übergeben werden. Dieser dient als Nachrichten-ID (siehe Message Exchange (MSX-Befehle Teil 1)).

_MsxItem

Damit wird ein neues Element innerhalb der Nachricht geöffnet, ein bereits geöffnetes wird automatisch geschlossen. Im dritten Parameter muss ein Wert vom Typ int ungleich 0 übergeben werden. Dieser dient als Element-ID (siehe Message Exchange (MSX-Befehle Teil 1)) und darf sich wiederholen. _MsxItem kann nur verwendet werden, wenn zuvor eine Nachricht (_MsxMessage) geöffnet wurde.

_MsxData

Hierbei werden die Daten in ein Element geschrieben. Dies geschieht seriell. Optional kann in einem vierten Parameter die maximale Datenlänge angegeben werden. _MsxData kann nur verwendet werden, wenn zuvor ein Element (_MsxItem) geöffnet wurde.

_MsxEnd

Schließt die offene Nachricht. Nach dem Schreiben von _MsxEnd wird der Inhalt des Puffers in das Kommunikationsmedium übertragen. Erst dadurch ist die Nachricht komplett und für den Empfänger lesbar.

// In den Nachrichtenkanal schreiben
tMsx->MsxWrite(_MsxMessage,1);
tMsx->MsxWrite(_MsxItem,1);
tMsx->MsxWrite(_MsxData,tSender);
tMsx->MsxWrite(_MsxItem,2);
tMsx->MsxWrite(_MsxData,tAction);
tMsx->MsxWrite(_MsxData,tRecordID);
tMsx->MsxWrite(_MsxEnd,0);
MsxRead()

Gelesen werden kann eine Nachricht über den Befehl MsxRead(). Auch dieser Funktion muss übergeben werden, welcher Teil der Nachricht gelesen werden soll. Auch hier gilt, dass ein Teil nur dann gelesen werden kann, wenn der übergeordnete Teil gelesen wurde. Die gelesenen Daten werden in eine Variable gespeichert, welche der Funktion übergeben werden muss. Die Nachricht wird durch das Lesen von _MsxEnd geschlossen. Alle Daten die bis dahin nicht gelesen worden sind, werden verworfen. Erst mit dem Schließen der Nachricht, mittels _MsxEnd, kann eine neue Nachricht gelesen werden. Sind keine weiteren Nachrichten im Nachrichtenkanal vorhanden wird dies über den Rückgabewert der Funktion übermittelt. Der Rückgabewert variiert dabei je nach verwendetem Medium. Bei der Verwendung von Sockets wird _ErrTimeout zurückgegeben, wenn keine weiteren Daten vorhanden sind und _ErrSckRead, wenn die Verbindung beendet wurde. Falls in einer externen Datei keine weiteren Nachrichten vorhanden sind, ist das Resultat _ErrData. Innerhalb einer Nachricht wird über den Rückgabewert 0 signalisiert, dass kein weiteres Element vorhanden ist.

// Aus dem Nachrichtenkanal lesen
tMsx->MsxRead(_MsxMessage,tMessageID);
tMsx->MsxRead(_MsxItem,tItemID);

while (tItemID != 0)
{
  switch (tItemID)
  {
    case 1 :
    {
      tMsx->MsxRead(_MsxData,tSenderName);
      ...
    }

    case 2 :
    {
      tMsx->MsxRead(_MsxData,tAction);
      tMsx->MsxRead(_MsxData,tRecordID);
      ...
    }
  }

  tMsx->MsxRead(_MsxItem,tItemID);
}

tMsx->MsxRead(_MsxEnd,0);
MsxWriteMem() und MsxReadMem()

Die Funktionen MsxReadMem() und MsxWriteMem() dienen um den Inhalt aus einem Nachrichtenkanal in ein Memory-Objekt zu lesen, bzw. den Inhalt aus einem Memory-Objekt in einen Nachrichtenkanal zu schreiben. Vor dem Aufruf beider Funktionen muss zuvor ein Nachrichtenbereich (MsxRead(_MsxItem, …) bzw. MsxWrite(_MsxItem, …))geöffnet sein. Der Funktion wird übergeben ab welcher Stelle wie viel geschrieben/gelesen werden soll. Beim Lesen muss diese Länge identisch mit der beim Schreiben angegebenen Länge sein. Um dies bei variablen Größen zu ermöglichen, muss die Größe beim Schreiben mit gesendet werden. Als Resultat erhält man die Anzahl der gelesenen/geschriebenen Bytes oder, falls ein Fehler Auftritt, den entsprechenden Fehlercode zurück.

// Aus einem Memory-Objekt in den Nachrichtenkanal schreiben
tMsx->MsxWrite(_MsxMessage, 1);
tMsx->MsxWrite(_MsxItem, 1);

// Variable Größe des Memory-Objekt mitsenden
tMsx->MsxWrite(_MsxData, 1, tMem->spLen);
tMsx->MsxWriteMem(tMem, 1, tMem->spLen);

// Aus dem Nachrichtenkanal in ein Memory-Objekt lesen
tMsx->MsxRead(_MsxMessage, tMessageID);
tMsx->MsxRead(_MsxItem, tItemID);

// Variable Größe des Memory-Objekts lesen
tMsx->MsxRead(_MsxData, tMemLen);
tMsx->MsxReadMem(tMem, tMem->spLen, tMemLen);
MsxClose()

Der Befehl MsxClose() schließt nur den Nachrichtenkanal. Der zugrundeliegende Datei- oder Socketdeskriptor bleibt weiterhin offen und muss extra geschlossen werden. Vor dem Schließen des Nachrichtenkanals muss die Nachricht unbedingt mit _MsxEnd beendet worden sein.

// Nachrichtenkanal schließen
tMsx->MsxClose();

// Zusätzliche Deskriptoren müssen ebenfalls geschlossen werden
tFsi->FsiClose();
Keine Kommentare

Kommentar abgeben