Usare uno pseudoterminale per far comunicare bidirezionalmente due programmi

Da Gambas-it.org - Wikipedia.

L'intenzione è di far comunicare bidirezionalmente mediante l'uso di un file pseudoterminale due programmi: uno Master e l'altro Slave.
In tal caso il programma Master invia dati al programma Slave, il quale riceve detti dati e ne invia altri al programma Master. Più precisamente ogni dato scritto (in uscita) dal programma Master, appare in entrata sul programma Slave; ed ogni dato scritto (in uscita) dal programma Slave, appare in entrata nel programma Master.

I programmi (il Master e lo Slave) possono essere indifferentemente entrambi programmi Gambas, oppure un programma Gambas ed un programma esterno scritto in altro linguaggio.
Si farà comunque uso di alcune funzioni esterne contenute nella libreria libc.so.6 .


Esempio pratico

Nell'esempio che segue, abbiamo i codici di un programma Master e di un programma Slave, entrambi in linguaggio Gambas, ciascuno dei quali invia dati all'altro e riceve dati dall'altro.

Va lanciato prima il programma Master, poi il programma Slave.

Il codice del programma Master

Il codice del programma Master è il seguente:

Library "libc:6"

' int grantpt (int __fd)
' Chown the slave to the calling user.
Private Extern grantpt(__fd As Integer) As Integer
 
' int unlockpt (int __fd)
' Release an internal lock so the slave can be opened.
Private Extern unlockpt(__fd As Integer) As Integer

' int ptsname_r (int __fd, char *__buf, size_t __buflen)
' Store at most BUFLEN characters of the pathname of the slave pseudo
' terminal associated with the master FD is open on in BUF.
Private Extern ptsname_r(__fd As Integer, __buf As Byte[], __buflen As Long) As Integer


Public Sub Main()
 
 Dim fl As File
 Dim i As Integer
 Dim percorsoSlave As New Byte[32]
 Dim introitus, exitus As String
 
 fl = Open "/dev/ptmx" For Read Write
   
' Accesso di grant al programma 'Slave':
 i = grantpt(fl.Handle)
 If i < 0 Then Error.Raise("Errore alla funzione 'grantpt()' !")
   
' Sblocca il programma 'Slave':
 i = unlockpt(fl.Handle)
 If i < 0 Then Error.Raise("Errore alla funzione 'unlockpt()' !")
   
' Ottiene il percorso del programma 'Slave':
 i = ptsname_r(fl.Handle, percorsoSlave, percorsoSlave.Count)
 If i < 0 Then Error.Raise("Errore alla funzione 'ptsname_r()' !")
   
 Print "Uso del file pts: "; String@(percorsoSlave.Data); "  (da riportare in 'Open' del programma 'Slave')"
  
 exitus = "master"
   
 Do
   Read #fl, introitus, -256
   If Len(introitus) > 0 Then 
     Print "Lettura"
     Print "Letti "; Len(introitus); " byte: "; introitus
     Print
     Print "Scrittura: "; exitus
     Write #fl, exitus
     Print "Scritti "; Len(exitus); " byte\n"
   Endif
   Wait 1
 Loop
   
 fl.Close
 
End


Il codice del programma Slave

Dopo aver lanciato il programma Master, si dovrà avere cura di annotare il file pseudoterminale generato ed utilizzato (mostrato nella console del Master). Il percorso dello pseudoterminale andrà inserito nell'apposita linea di Open del codice del programma Slave, affinché possa essere aperto in lettura ed in scrittura.

Il codice del programma Slave è il seguente:

Library "libc:6"

Private Const TCSANOW As Integer = 0

' int tcgetattr (int __fd, struct termios *__termios_p)
' Put the state of FD into *TERMIOS_P.
Private Extern tcgetattr(__fd As Integer, __termios_p As Pointer) As Integer

' void cfmakeraw (struct termios *__termios_p)
' Set *TERMIOS_P to indicate raw mode.
Private Extern cfmakeraw(__termios_p As Pointer)

' int tcsetattr (int __fd, int __optional_actions, const struct termios *__termios_p)
' Set the state of FD to *TERMIOS_P.
Private Extern tcsetattr(__fd As Integer, __optional_actions As Integer, __termios_p As Pointer) As Integer 


Public Sub Main()
 
 Dim termios As Pointer
 Dim fl As File
 Dim i As Integer
 Dim introitus, exitus As String
 
 termios = Alloc(SizeOf(gb.Byte), 60)
   
' Va inserito il numero del file dello pseudoterminale mostrato nella console del programma "Master":
 fl = Open "/dev/pts/..." For Read Write
   
 i = tcgetattr(fl.Handle, termios)
 If i < 0 Then Error.Raise("Errore alla funzione 'tcgetattr()' !")
   
 cfmakeraw(termios)
 tcsetattr(fl.Handle, TCSANOW, termios)
   
 exitus = "slave"
   
 Do
   Print "Lettura"
   Read #fl, introitus, -256
   Print "Letti "; Len(introitus); " byte: "; introitus
   Print
   Print "Scrittura: "; exitus
   Write #fl, exitus
   Print "Scritti "; Len(exitus); " byte\n"
   Wait 1
 Loop
 
 Free(termios)
 fl.Close
  
End


Riferimenti